Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>google.javascript.jscomp.mozilla.rhino.ast.TryStatement;
import com.google.javascript.jscomp.mozilla.rhino.ast.UnaryExpression;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableDeclaration;
import com.google.javascript.jscomp.mozilla.rhino.ast.VariableInitializer;
import com.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop;
import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement;
import com.google.javascript.jscomp.parsing.Config.LanguageMode;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import java.util.Set;
/**
* IRFactory transforms the new AST to the old AST.
*
*/
public class IRFactory {
private final String sourceString;
private final String sourceName;
private final Config config;
private final ErrorReporter errorReporter;
private final TransformDispatcher transformDispatcher;
// non-static for thread safety
private final Set<String> ALLOWED_DIRECTIVES = Sets.newHashSet("use strict");
private static final Set<String> ES5_RESERVED_KEYWORDS =
ImmutableSet.of(
// From Section 7.6.1.2
"class", "const", "enum", "export", "extends", "import", "super");
private static final Set<String> ES5_STRICT_RESERVED_KEYWORDS =
ImmutableSet.of(
// From Section 7.6.1.2
"class", "const", "enum", "export", "extends", "import", "super",
"implements", "interface", "let", "package", "private", "protected",
"public", "static", "yield");
private final Set<String> reservedKeywords;
// @license text gets appended onto the fileLevelJsDocBuilder as found,
// and stored in JSDocInfo for placeholder node.
Node rootNodeJsDocHolder = new Node(Token.SCRIPT);
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder =
rootNodeJsDocHolder.getJsDocBuilderForNode();
J
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>SDocInfo fileOverviewInfo = null;
// Use a template node for properties set on all nodes to minimize the
// memory footprint associated with these.
private Node templateNode;
// TODO(johnlenz): Consider creating a template pool for ORIGINALNAME_PROP.
private IRFactory(String sourceString,
String sourceName,
Config config,
ErrorReporter errorReporter) {
this.sourceString = sourceString;
this.sourceName = sourceName;
this.config = config;
this.errorReporter = errorReporter;
this.transformDispatcher = new TransformDispatcher();
// The template node properties are applied to all nodes in this transform.
this.templateNode = createTemplateNode();
switch (config.languageMode) {
case ECMASCRIPT3:
// Reserved words are handled by the Rhino parser.
reservedKeywords = null;
break;
case ECMASCRIPT5:
reservedKeywords = ES5_RESERVED_KEYWORDS;
break;
case ECMASCRIPT5_STRICT:
reservedKeywords = ES5_STRICT_RESERVED_KEYWORDS;
break;
default:
throw new IllegalStateException("unknown language mode");
}
}
// Create a template node to use as a source of common attributes, this allows
// the prop structure to be shared among all the node from this source file.
// This reduces the cost of these properties to O(nodes) to O(files).
private Node createTemplateNode() {
// The Node type choice is arbitrary.
Node templateNode = new Node(Token.SCRIPT);
templateNode.putProp(Node.SOURCENAME_PROP, sourceName);
return templateNode;
}
public static Node transformTree(AstRoot node,
String sourceString,
Config config,
ErrorReporter errorReporter) {
IRFactory irFactory = new IRFactory(sourceString, node.getSourceName(),
config, errorReporter);
Node irNode = irFactory.transform(node);
if (node.getComments() != null) {
for (Comment comment : node.getComments()) {
if (comment.getCommentType() == JSDOC && !comment.isParsed()) {
irFactory.handlePossibleFileOverviewJsDoc(comment);
}
}
}
irFactory.setFileOverviewJsDoc(irNode);
return ir
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Node;
}
private void setFileOverviewJsDoc(Node irNode) {
// Only after we've seen all @fileoverview entries, attach the
// last one to the root node, and copy the found license strings
// to that node.
irNode.setJSDocInfo(rootNodeJsDocHolder.getJSDocInfo());
if (fileOverviewInfo != null) {
if ((irNode.getJSDocInfo() != null) &&
(irNode.getJSDocInfo().getLicense() != null)) {
fileOverviewInfo.setLicense(irNode.getJSDocInfo().getLicense());
}
irNode.setJSDocInfo(fileOverviewInfo);
}
}
private Node transformBlock(AstNode node) {
Node irNode = transform(node);
if (irNode.getType() != Token.BLOCK) {
if (irNode.getType() == Token.EMPTY) {
irNode.setType(Token.BLOCK);
irNode.setWasEmptyNode(true);
} else {
Node newBlock = newNode(Token.BLOCK, irNode);
newBlock.setLineno(irNode.getLineno());
newBlock.setCharno(irNode.getCharno());
irNode = newBlock;
}
}
return irNode;
}
/**
* @return true if the jsDocParser represents a fileoverview.
*/
private boolean handlePossibleFileOverviewJsDoc(
JsDocInfoParser jsDocParser) {
if (jsDocParser.getFileOverviewJSDocInfo() != fileOverviewInfo) {
fileOverviewInfo = jsDocParser.getFileOverviewJSDocInfo();
return true;
}
return false;
}
private void handlePossibleFileOverviewJsDoc(Comment comment) {
JsDocInfoParser jsDocParser = createJsDocInfoParser(comment);
comment.setParsed(true);
handlePossibleFileOverviewJsDoc(jsDocParser);
}
private JSDocInfo handleJsDoc(AstNode node) {
Comment comment = node.getJsDocNode();
if (comment != null) {
JsDocInfoParser jsDocParser = createJsDocInfoParser(comment);
comment.setParsed(true);
if (!handlePossibleFileOverviewJsDoc(jsDocParser)) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
return jsDocParser.retrieveAndResetParsedJSDocInfo();
}
}
return null;
}
irNode.setLineno(lineno);
int charno = position2charno(node.getAbsolutePosition());
irNode.setCharno(charno);
}
}
}
/**
* Creates a JsDocInfoParser and parses the JsDoc string.
*
* Used both for handling individual JSDoc comments and for handling
* file-level JSDoc comments (@fileoverview and @license).
*
* @param node The JsDoc Comment node to parse.
* @return A JSDocInfoParser. Will contain either fileoverview jsdoc, or
* normal jsdoc, or no jsdoc (if the method parses to the wrong level).
*/
private JsDocInfoParser createJsDocInfoParser(Comment node) {
String comment = node.getValue();
int lineno = node.getLineno();
int position = node.getAbsolutePosition();
// The JsDocInfoParser expects the comment without the initial '/**'.
int numOpeningChars = 3;
JsDocInfoParser jsdocParser =
new JsDocInfoParser(
new JsDocTokenStream(comment.substring(numOpeningChars),
lineno,
position2charno(position) + numOpeningChars),
node,
sourceName,
config,
errorReporter);
jsdocParser.setFileLevelJsDocBuilder(fileLevelJsDocBuilder);
jsdocParser.setFileOverviewJSDocInfo(fileOverviewInfo);
jsdocParser.parse();
return jsdocParser;
}
private int position2charno(int position) {
int lineIndex = sourceString.lastIndexOf('\n', position);
if (lineIndex == -1) {
return position;
} else {
// Subtract one for initial position being 0.
return position - lineIndex - 1;
}
}
private Node justTransform(AstNode node) {
return transformDispatcher.process(node);
}
private class TransformDispatcher extends TypeSafeDispatcher<Node> {
private Node processGeneric(
com.google.javascript.jscomp.mozilla.rhino.Node n) {
Node node = newNode(transformTokenType(n.getType()));
return node;
}
@Override
Node process
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> processKeywordLiteral(KeywordLiteral literalNode) {
return newNode(transformTokenType(literalNode.getType()));
}
@Override
Node processLabel(Label labelNode) {
return newStringNode(Token.LABEL_NAME, labelNode.getName());
}
@Override
Node processLabeledStatement(LabeledStatement statementNode) {
Node node = newNode(Token.LABEL);
Node prev = null;
Node cur = node;
for (Label label : statementNode.getLabels()) {
if (prev != null) {
prev.addChildToBack(cur);
}
cur.addChildToBack(transform(label));
cur.setLineno(label.getLineno());
int clauseAbsolutePosition =
position2charno(label.getAbsolutePosition());
cur.setCharno(clauseAbsolutePosition);
prev = cur;
cur = newNode(Token.LABEL);
}
prev.addChildToBack(transform(statementNode.getStatement()));
return node;
}
@Override
Node processName(Name nameNode) {
return processName(nameNode, false);
}
Node processName(Name nameNode, boolean asString) {
if (asString) {
return newStringNode(Token.STRING, nameNode.getIdentifier());
} else {
if (isReservedKeyword(nameNode.getIdentifier())) {
errorReporter.error(
"identifier is a reserved word",
sourceName,
nameNode.getLineno(), "", 0);
}
return newStringNode(Token.NAME, nameNode.getIdentifier());
}
}
/**
* @return Whether the
*/
private boolean isReservedKeyword(String identifier) {
return reservedKeywords != null && reservedKeywords.contains(identifier);
}
@Override
Node processNewExpression(NewExpression exprNode) {
return processFunctionCall(exprNode);
}
@Override
Node processNumberLiteral(NumberLiteral literalNode) {
return newNumberNode(literalNode.getNumber());
}
@Override
Node processObjectLiteral(ObjectLiteral literalNode) {
if (literalNode.isDestructuring()) {
reportDestructuringAssign(literalNode);
}
Node node = newNode(Token.OBJECTLIT);
for (ObjectProperty el : literalNode.getElements()) {
if (config.languageMode == LanguageMode.E
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>CMASCRIPT3) {
if (el.isGetter()) {
reportGetter(el);
continue;
} else if (el.isSetter()) {
reportSetter(el);
continue;
}
}
Node key = transformAsString(el.getLeft());
Node value = transform(el.getRight());
if (el.isGetter()) {
key.setType(Token.GET);
Preconditions.checkState(value.getType() == Token.FUNCTION);
if (getFnParamNode(value).hasChildren()) {
reportGetterParam(el.getLeft());
}
} else if (el.isSetter()) {
key.setType(Token.SET);
Preconditions.checkState(value.getType() == Token.FUNCTION);
if (!getFnParamNode(value).hasOneChild()) {
reportSetterParam(el.getLeft());
}
}
key.addChildToFront(value);
node.addChildToBack(key);
}
return node;
}
/**
* @param fnNode The function.
* @return The Node containing the Function parameters.
*/
Node getFnParamNode(Node fnNode) {
// Function NODE: [ FUNCTION -> NAME, LP -> ARG1, ARG2, ... ]
Preconditions.checkArgument(fnNode.getType() == Token.FUNCTION);
return fnNode.getFirstChild().getNext();
}
@Override
Node processObjectProperty(ObjectProperty propertyNode) {
return processInfixExpression(propertyNode);
}
@Override
Node processParenthesizedExpression(ParenthesizedExpression exprNode) {
Node node = transform(exprNode.getExpression());
node.putProp(Node.PARENTHESIZED_PROP, Boolean.TRUE);
return node;
}
@Override
Node processPropertyGet(PropertyGet getNode) {
return newNode(
Token.GETPROP,
transform(getNode.getTarget()),
transformAsString(getNode.getProperty()));
}
@Override
Node processRegExpLiteral(RegExpLiteral literalNode) {
Node literalStringNode = newStringNode(literalNode.getValue());
// assume it's on the same line.
literalStringNode.setLineno(literalNode.getLineno());
Node node = newNode(Token.REGEXP, literalStringNode);
String flags = literalNode.getFlags();
if (flags !=
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> null && !flags.isEmpty()) {
Node flagsNode = newStringNode(flags);
// Assume the flags are on the same line as the literal node.
flagsNode.setLineno(literalNode.getLineno());
node.addChildToBack(flagsNode);
}
return node;
}
@Override
Node processReturnStatement(ReturnStatement statementNode) {
Node node = newNode(Token.RETURN);
if (statementNode.getReturnValue() != null) {
node.addChildToBack(transform(statementNode.getReturnValue()));
}
return node;
}
@Override
Node processScope(Scope scopeNode) {
return processGeneric(scopeNode);
}
@Override
Node processStringLiteral(StringLiteral literalNode) {
Node n = newStringNode(literalNode.getValue());
return n;
}
@Override
Node processSwitchCase(SwitchCase caseNode) {
Node node;
if (caseNode.isDefault()) {
node = newNode(Token.DEFAULT);
} else {
AstNode expr = caseNode.getExpression();
node = newNode(Token.CASE, transform(expr));
}
Node block = newNode(Token.BLOCK);
block.putBooleanProp(Node.SYNTHETIC_BLOCK_PROP, true);
block.setLineno(caseNode.getLineno());
block.setCharno(position2charno(caseNode.getAbsolutePosition()));
if (caseNode.getStatements() != null) {
for (AstNode child : caseNode.getStatements()) {
block.addChildToBack(transform(child));
}
}
node.addChildToBack(block);
return node;
}
@Override
Node processSwitchStatement(SwitchStatement statementNode) {
Node node = newNode(Token.SWITCH,
transform(statementNode.getExpression()));
for (AstNode child : statementNode.getCases()) {
node.addChildToBack(transform(child));
}
return node;
}
@Override
Node processThrowStatement(ThrowStatement statementNode) {
return newNode(Token.THROW,
transform(statementNode.getExpression()));
}
@Override
Node processTryStatement(TryStatement statementNode) {
Node node = newNode(Token.TRY,
transformBlock(statementNode.getTryBlock()));
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> return Token.XMLATTR;
case com.google.javascript.jscomp.mozilla.rhino.Token.XMLEND:
return Token.XMLEND;
case com.google.javascript.jscomp.mozilla.rhino.Token.TO_OBJECT:
return Token.TO_OBJECT;
case com.google.javascript.jscomp.mozilla.rhino.Token.TO_DOUBLE:
return Token.TO_DOUBLE;
case com.google.javascript.jscomp.mozilla.rhino.Token.GET:
return Token.GET;
case com.google.javascript.jscomp.mozilla.rhino.Token.SET:
return Token.SET;
case com.google.javascript.jscomp.mozilla.rhino.Token.CONST:
return Token.CONST;
case com.google.javascript.jscomp.mozilla.rhino.Token.SETCONST:
return Token.SETCONST;
case com.google.javascript.jscomp.mozilla.rhino.Token.DEBUGGER:
return Token.DEBUGGER;
}
// Token without name
throw new IllegalStateException(String.valueOf(token));
}
// Simple helper to create nodes and set the initial node properties.
private Node newNode(int type) {
return new Node(type).clonePropsFrom(templateNode);
}
private Node newNode(int type, Node child1) {
return new Node(type, child1).clonePropsFrom(templateNode);
}
private Node newNode(int type, Node child1, Node child2) {
return new Node(type, child1, child2).clonePropsFrom(templateNode);
}
private Node newNode(int type, Node child1, Node child2, Node child3) {
return new Node(type, child1, child2, child3).clonePropsFrom(templateNode);
}
private Node newStringNode(String value) {
return Node.newString(value).clonePropsFrom(templateNode);
}
private Node newStringNode(int type, String value) {
return Node.newString(type, value).clonePropsFrom(templateNode);
}
private Node newNumberNode(Double value) {
return Node.newNumber(value).clonePropsFrom(templateNode);
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> in a prototype definition and as an object
* literal key, we rename it only if it satisifies both renaming policies.
*
*/
class RenamePrototypes implements CompilerPass {
private final AbstractCompiler compiler;
private final boolean aggressiveRenaming;
private final char[] reservedCharacters;
/** Previously used prototype renaming map. */
private final VariableMap prevUsedRenameMap;
/**
* The Property class encapsulates the information needed for renaming
* a method or member.
*/
private class Property {
String oldName;
String newName;
int prototypeCount;
int objLitCount;
int refCount;
Property(String name) {
this.oldName = name;
this.newName = null;
this.prototypeCount = 0;
this.objLitCount = 0;
this.refCount = 0;
}
int count() {
return prototypeCount + objLitCount + refCount;
}
boolean canRename() {
if (this.prototypeCount > 0 && this.objLitCount == 0) {
return canRenamePrototypeProperty();
}
if (this.objLitCount > 0 && this.prototypeCount == 0) {
return canRenameObjLitProperty();
}
// We're not sure what kind of property this is, so we're conservative.
// Note that we still want to try renaming the property even when both
// counts are zero. It may be a property added to an object at runtime,
// like: o.newProp = x;
return canRenamePrototypeProperty() && canRenameObjLitProperty();
}
private boolean canRenamePrototypeProperty() {
if (compiler.getCodingConvention().isExported(oldName)) {
// an externally visible name should not be renamed.
return false;
}
if (compiler.getCodingConvention().isPrivate(oldName)) {
// private names can be safely renamed. Rename!
return true;
}
if (aggressiveRenaming) {
return true;
}
for (int i = 0, n = oldName.length(); i < n; i++) {
char ch = oldName.charAt(i);
if (Character.isUpperCase(ch) || !Character.isLetter(ch)) {
return true;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(first);
add("]");
break;
case Token.LP:
add("(");
addList(first);
add(")");
break;
case Token.COMMA:
Preconditions.checkState(childCount == 2);
addList(first, false, context);
break;
case Token.NUMBER:
Preconditions.checkState(
childCount ==
((n.getParent() != null &&
n.getParent().getType() == Token.OBJECTLIT) ? 1 : 0));
cc.addNumber(n.getDouble());
break;
case Token.TYPEOF:
case Token.VOID:
case Token.NOT:
case Token.BITNOT:
case Token.POS: {
// All of these unary operators are right-associative
Preconditions.checkState(childCount == 1);
cc.addOp(NodeUtil.opToStrNoFail(type), false);
addExpr(first, NodeUtil.precedence(type));
break;
}
case Token.NEG: {
Preconditions.checkState(childCount == 1);
// It's important to our sanity checker that the code
// we print produces the same AST as the code we parse back.
// NEG is a weird case because Rhino parses "- -2" as "2".
if (n.getFirstChild().getType() == Token.NUMBER) {
cc.addNumber(-n.getFirstChild().getDouble());
} else {
cc.addOp(NodeUtil.opToStrNoFail(type), false);
addExpr(first, NodeUtil.precedence(type));
}
break;
}
case Token.HOOK: {
Preconditions.checkState(childCount == 3);
int p = NodeUtil.precedence(type);
addLeftExpr(first, p + 1, context);
cc.addOp("?", true);
addExpr(first.getNext(), 1);
cc.addOp(":", true);
addExpr(last, 1);
break;
}
case Token.REGEXP:
if (first.getType() != Token.STRING ||
last.getType() != Token.STRING) {
throw new Error("Expected children to be strings");
}
String regexp = regexpEscape(first.getString(), outputCharsetEncoder);
// I only use
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> * node with the associated skipIndexes array. This is a space optimization
* since we avoid creating a whole Node object for each empty array literal
* slot.
* @param firstInList The first in the node list (chained through the next
* property).
*/
void addArrayList(Node firstInList) {
boolean lastWasEmpty = false;
for (Node n = firstInList; n != null; n = n.getNext()) {
if (n != firstInList) {
cc.listSeparator();
}
addExpr(n, 1);
lastWasEmpty = n.getType() == Token.EMPTY;
}
if (lastWasEmpty) {
cc.listSeparator();
}
}
void addCaseBody(Node caseBody) {
cc.beginCaseBody();
add(caseBody);
cc.endCaseBody();
}
void addAllSiblings(Node n) {
for (Node c = n; c != null; c = c.getNext()) {
add(c);
}
}
/** Outputs a js string, using the optimal (single/double) quote character */
static String jsString(String s, CharsetEncoder outputCharsetEncoder) {
int singleq = 0, doubleq = 0;
// could count the quotes and pick the optimal quote character
for (int i = 0; i < s.length(); i++) {
switch (s.charAt(i)) {
case '"': doubleq++; break;
case '\'': singleq++; break;
}
}
String doublequote, singlequote;
char quote;
if (singleq < doubleq) {
// more double quotes so escape the single quotes
quote = '\'';
doublequote = "\"";
singlequote = "\\\'";
} else {
// more single quotes so escape the doubles
quote = '\"';
doublequote = "\\\"";
singlequote = "\'";
}
return strEscape(s, quote, doublequote, singlequote, "\\\\",
outputCharsetEncoder);
}
/** Escapes regular expression */
static String regexpEscape(String s, CharsetEncoder outputCharsetEncoder) {
return strEscape(s, '/', "\"", "'", "\\", outputCharsetEncoder);
}
/**
* Escapes the given string to a double quoted (
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>") JavaScript/JSON string
*/
static String escapeToDoubleQuotedJsString(String s) {
return strEscape(s, '"', "\\\"", "\'", "\\\\", null);
}
/* If the user doesn't want to specify an output charset encoder, assume
they want Latin/ASCII characters only.
*/
static String regexpEscape(String s) {
return regexpEscape(s, null);
}
/** Helper to escape javascript string as well as regular expression */
static String strEscape(String s, char quote,
String doublequoteEscape,
String singlequoteEscape,
String backslashEscape,
CharsetEncoder outputCharsetEncoder) {
StringBuilder sb = new StringBuilder(s.length() + 2);
sb.append(quote);
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
switch (c) {
case '\0': sb.append("\\0"); break;
case '\n': sb.append("\\n"); break;
case '\r': sb.append("\\r"); break;
case '\t': sb.append("\\t"); break;
case '\\': sb.append(backslashEscape); break;
case '\"': sb.append(doublequoteEscape); break;
case '\'': sb.append(singlequoteEscape); break;
case '>': // Break --> into --\> or ]]> into ]]\>
if (i >= 2 &&
((s.charAt(i - 1) == '-' && s.charAt(i - 2) == '-') ||
(s.charAt(i - 1) == ']' && s.charAt(i - 2) == ']'))) {
sb.append("\\>");
} else {
sb.append(c);
}
break;
case '<':
// Break </script into <\/script
final String END_SCRIPT = "/script";
// Break <!-- into <\!--
final String START_COMMENT = "!--";
if (s.regionMatches(true, i + 1, END_SCRIPT, 0,
END_SCRIPT.length())) {
sb.append("<\\");
} else if (s.regionMatches(false, i + 1, START_COMMENT, 0,
START_COMMENT.length())) {
sb.append("<\\
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>");
} else {
sb.append(c);
}
break;
default:
// If we're given an outputCharsetEncoder, then check if the
// character can be represented in this character set.
if (outputCharsetEncoder != null) {
if (outputCharsetEncoder.canEncode(c)) {
sb.append(c);
} else {
// Unicode-escape the character.
appendHexJavaScriptRepresentation(sb, c);
}
} else {
// No charsetEncoder provided - pass straight latin characters
// through, and escape the rest. Doing the explicit character
// check is measurably faster than using the CharsetEncoder.
if (c > 0x1f && c <= 0x7f) {
sb.append(c);
} else {
// Other characters can be misinterpreted by some js parsers,
// or perhaps mangled by proxies along the way,
// so we play it safe and unicode escape them.
appendHexJavaScriptRepresentation(sb, c);
}
}
}
}
sb.append(quote);
return sb.toString();
}
static String identifierEscape(String s) {
// First check if escaping is needed at all -- in most cases it isn't.
if (NodeUtil.isLatin(s)) {
return s;
}
// Now going through the string to escape non-latin characters if needed.
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
// Identifiers should always go to Latin1/ ASCII characters because
// different browser's rules for valid identifier characters are
// crazy.
if (c > 0x1F && c < 0x7F) {
sb.append(c);
} else {
appendHexJavaScriptRepresentation(sb, c);
}
}
return sb.toString();
}
/**
* @param maxCount The maximum number of children to look for.
* @return The number of children of this node that are non empty up to
* maxCount.
*/
private static int getNonEmptyChildCount(Node n, int maxCount) {
int i = 0;
Node c = n.getFirstChild();
for (; c
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>can.c and jsscan.h
* in the jsref package.
*
* @see Parser
*
*/
public class TokenStream
{
/*
* For chars - because we need something out-of-range
* to check. (And checking EOF by exception is annoying.)
* Note distinction from EOF token type!
*/
private final static int
EOF_CHAR = -1;
public TokenStream(Parser parser, Reader sourceReader, String sourceString,
int lineno)
{
this.parser = parser;
this.lineno = lineno;
if (sourceReader != null) {
if (sourceString != null) Kit.codeBug();
this.sourceReader = sourceReader;
this.sourceBuffer = new char[512];
this.sourceEnd = 0;
} else {
if (sourceString == null) Kit.codeBug();
this.sourceString = sourceString;
this.sourceEnd = sourceString.length();
}
this.sourceCursor = 0;
}
/* This function uses the cached op, string and number fields in
* TokenStream; if getToken has been called since the passed token
* was scanned, the op or string printed may be incorrect.
*/
String tokenToString(int token)
{
if (Token.printTrees) {
String name = Token.name(token);
switch (token) {
case Token.STRING:
case Token.REGEXP:
case Token.NAME:
return name + " `" + this.string + "'";
case Token.NUMBER:
return "NUMBER " + this.number;
}
return name;
}
return "";
}
public static boolean isKeyword(String s)
{
return Token.EOF != stringToKeyword(s);
}
private static int stringToKeyword(String name)
{
// #string_id_map#
// The following assumes that Token.EOF == 0
final int
Id_break = Token.BREAK,
Id_case = Token.CASE,
Id_continue = Token.CONTINUE,
Id_default = Token.DEFAULT,
Id_delete = Token.DELPROP,
Id_do = Token.DO,
Id_else = Token.ELSE,
Id_export
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.RESERVED,
Id_transient = Token.RESERVED,
Id_try = Token.TRY,
Id_volatile = Token.RESERVED;
int id;
String s = name;
// #generated# Last update: 2001-06-01 17:45:01 CEST
L0: { id = 0; String X = null; int c;
L: switch (s.length()) {
case 2: c=s.charAt(1);
if (c=='f') { if (s.charAt(0)=='i') {id=Id_if; break L0;} }
else if (c=='n') { if (s.charAt(0)=='i') {id=Id_in; break L0;} }
else if (c=='o') { if (s.charAt(0)=='d') {id=Id_do; break L0;} }
break L;
case 3: switch (s.charAt(0)) {
case 'f':
if (s.charAt(2)=='r' && s.charAt(1)=='o') {
id=Id_for; break L0;
} break L;
case 'i':
if (s.charAt(2)=='t' && s.charAt(1)=='n') {
id=Id_int; break L0;
} break L;
case 'n':
if (s.charAt(2)=='w' && s.charAt(1)=='e') {
id=Id_new; break L0;
} break L;
case 't':
if (s.charAt(2)=='y' && s.charAt(1)=='r') {
id=Id_try; break L0;
} break L;
case 'v':
if (s.charAt(2)=='r' && s.charAt(1)=='a') {
id=Id_var; break L0;
} break L;
} break L;
case 4: switch (s.charAt(0)) {
case 'b': X="byte";id=Id_byte; break L;
case 'c': c=s.charAt(3);
if (c=='e') { if (s.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>charAt(2)=='s' && s.charAt(1)=='a') {
id=Id_case; break L0;} }
else if (c=='r') {
if (s.charAt(2)=='a' && s.charAt(1)=='h') {
id=Id_char; break L0;
}
}
break L;
case 'e': c=s.charAt(3);
if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {
id=Id_else; break L0;} }
else if (c=='m') {
if (s.charAt(2)=='u' && s.charAt(1)=='n') {
id=Id_enum; break L0;} }
break L;
case 'g': X="goto";id=Id_goto; break L;
case 'l': X="long";id=Id_long; break L;
case 'n': X="null";id=Id_null; break L;
case 't': c=s.charAt(3);
if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {
id=Id_true; break L0;} }
else if (c=='s') {
if (s.charAt(2)=='i' && s.charAt(1)=='h') {
id=Id_this; break L0;} }
break L;
case 'v': X="void";id=Id_void; break L;
case 'w': X="with";id=Id_with; break L;
} break L;
case 5: switch (s.charAt(2)) {
case 'a': X="class";id=Id_class; break L;
case 'e': X="break";id=Id_break; break L;
case 'i': X="while";id=Id_while; break L;
case 'l': X="false";id=Id_false; break L;
case 'n': c=s.charAt(0);
if (c=='c') { X="const";id=Id_const; }
else if (c=='f') {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> X="final";id=Id_final; }
break L;
case 'o': c=s.charAt(0);
if (c=='f') { X="float";id=Id_float; }
else if (c=='s') { X="short";id=Id_short; }
break L;
case 'p': X="super";id=Id_super; break L;
case 'r': X="throw";id=Id_throw; break L;
case 't': X="catch";id=Id_catch; break L;
} break L;
case 6: switch (s.charAt(1)) {
case 'a': X="native";id=Id_native; break L;
case 'e': c=s.charAt(0);
if (c=='d') { X="delete";id=Id_delete; }
else if (c=='r') { X="return";id=Id_return; }
break L;
case 'h': X="throws";id=Id_throws; break L;
case 'm': X="import";id=Id_import; break L;
case 'o': X="double";id=Id_double; break L;
case 't': X="static";id=Id_static; break L;
case 'u': X="public";id=Id_public; break L;
case 'w': X="switch";id=Id_switch; break L;
case 'x': X="export";id=Id_export; break L;
case 'y': X="typeof";id=Id_typeof; break L;
} break L;
case 7: switch (s.charAt(1)) {
case 'a': X="package";id=Id_package; break L;
case 'e': X="default";id=Id_default; break L;
case 'i': X="finally";id=Id_finally; break L;
case 'o': X="boolean";id=Id_boolean; break L;
case 'r': X="private";id=Id_private; break L;
case 'x': X="extends";id=Id_extends; break L;
} break L;
case 8: switch (s.charAt(0)) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> case 'a': X="abstract";id=Id_abstract; break L;
case 'c': X="continue";id=Id_continue; break L;
case 'd': X="debugger";id=Id_debugger; break L;
case 'f': X="function";id=Id_function; break L;
case 'v': X="volatile";id=Id_volatile; break L;
} break L;
case 9: c=s.charAt(0);
if (c=='i') { X="interface";id=Id_interface; }
else if (c=='p') { X="protected";id=Id_protected; }
else if (c=='t') { X="transient";id=Id_transient; }
break L;
case 10: c=s.charAt(1);
if (c=='m') { X="implements";id=Id_implements; }
else if (c=='n') { X="instanceof";id=Id_instanceof; }
break L;
case 12: X="synchronized";id=Id_synchronized; break L;
}
if (X!=null && X!=s && !X.equals(s)) id = 0;
}
// #/generated#
// #/string_id_map#
if (id == 0) { return Token.EOF; }
return id & 0xff;
}
public static boolean isJSIdentifier(String s) {
int length = s.length();
if (length == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))
return false;
for (int i=1; i<length; i++) {
char c = s.charAt(i);
if (!Character.isJavaIdentifierPart(c)) {
if (c == '\\') {
if (! ((i + 5) < length)
&& (s.charAt(i + 1) == 'u')
&& 0 <= Kit.xDigitToInt(s.charAt(i + 2), 0)
&& 0 <= Kit.xDigitToInt(s.charAt(i + 3), 0)
&& 0 <= Kit.xDigitToInt(s.charAt(i + 4), 0)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> && 0 <= Kit.xDigitToInt(s.charAt(i + 5), 0)) {
return true;
}
}
return false;
}
}
return true;
}
protected final int getLineno() { return lineno; }
protected final int getCharno() { return charno; }
final String getString() { return string; }
final double getNumber() { return number; }
final boolean eof() { return hitEOF; }
public final int getToken() throws IOException
{
tokenno++;
// Check for pushed-back token
if (this.pushbackToken != Token.EOF) {
int result = this.pushbackToken;
this.pushbackToken = Token.EOF;
return result;
}
int c;
retry:
for (;;) {
// Eat whitespace, possibly sensitive to newlines.
for (;;) {
charno = -1;
c = getChar();
if (c == EOF_CHAR) {
return Token.EOF;
} else if (c == '\n') {
dirtyLine = false;
return Token.EOL;
} else if (!isJSSpace(c)) {
if (c != '-') {
dirtyLine = true;
}
break;
}
}
if (c == '@') return Token.XMLATTR;
// identifier/keyword/instanceof?
// watch out for starting with a <backslash>
boolean identifierStart;
boolean isUnicodeEscapeStart = false;
if (c == '\\') {
c = getChar();
if (c == 'u') {
identifierStart = true;
isUnicodeEscapeStart = true;
stringBufferTop = 0;
} else {
identifierStart = false;
ungetChar(c);
c = '\\';
}
} else {
identifierStart = Character.isJavaIdentifierStart((char)c);
if (identifierStart) {
stringBufferTop = 0;
addToString(c);
}
}
if (identifierStart) {
boolean containsEscape = isUnicodeEscapeStart;
for (;;) {
if (isUnicodeEscapeStart) {
// strictly speaking we should probably push-back
// all the bad characters if the <backslash>uXXXX
// sequence is malformed. But since there isn't a
//
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>') {
c = getChar();
if (c == 'x' || c == 'X') {
base = 16;
c = getChar();
} else if (isDigit(c)) {
base = 8;
} else {
addToString('0');
}
}
if (base == 16) {
while (0 <= Kit.xDigitToInt(c, 0)) {
addToString(c);
c = getChar();
}
} else {
while ('0' <= c && c <= '9') {
/*
* We permit 08 and 09 as decimal numbers, which
* makes our behavior a superset of the ECMA
* numeric grammar. We might not always be so
* permissive, so we warn about it.
*/
if (base == 8 && c >= '8') {
parser.addWarning("msg.bad.octal.literal",
c == '8' ? "8" : "9");
base = 10;
}
addToString(c);
c = getChar();
}
}
boolean isInteger = true;
if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {
isInteger = false;
if (c == '.') {
do {
addToString(c);
c = getChar();
} while (isDigit(c));
}
if (c == 'e' || c == 'E') {
addToString(c);
c = getChar();
if (c == '+' || c == '-') {
addToString(c);
c = getChar();
}
if (!isDigit(c)) {
parser.addError("msg.missing.exponent");
return Token.ERROR;
}
do {
addToString(c);
c = getChar();
} while (isDigit(c));
}
}
ungetChar(c);
String numString = getStringFromBuffer();
double dval;
if (base == 10 && !isInteger) {
try {
// Use Java conversion to number from string...
dval = Double.valueOf(numString).doubleValue();
}
catch (NumberFormatException ex) {
parser.addError("
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> return '0' <= c && c <= '9';
}
/**
* Tests whether the character is a valid JavaScript white space character
* as defined in ECMAScript 3rd edition.
*
* Note: jsscan.c uses C isspace() (which allows
* \v, I think.) note that code in getChar() implicitly accepts
* '\r' == \u000D as well.
*/
static boolean isJSSpace(int c)
{
if (c <= 127) {
return c == 0x20 || c == 0x9 || c == 0xC || c == 0xB;
} else {
return c == 0xA0
|| Character.getType((char)c) == Character.SPACE_SEPARATOR;
}
}
private static boolean isJSFormatChar(int c)
{
return c > 127 && Character.getType((char)c) == Character.FORMAT;
}
/**
* Gets the accumulated {@link JSDocInfo} and resets it.
* Obsolete
*/
JSDocInfo getAndResetJSDocInfo() {
return null;
}
/**
* Returns any {@link JSDocInfo} with a fileoverview tag that showed up.
* Obsolete
*/
JSDocInfo getFileOverviewJSDocInfo() {
return null;
}
/**
* Returns whether any {@link JSDocInfo} was accumulated.
* Obsolete
*/
boolean isPopulated() {
return false;
}
/**
* Parser calls the method when it gets / or /= in literal context.
*/
void readRegExp(int startToken)
throws IOException
{
stringBufferTop = 0;
if (startToken == Token.ASSIGN_DIV) {
// Miss-scanned /=
addToString('=');
} else {
if (startToken != Token.DIV) Kit.codeBug();
}
boolean inCharSet = false; // true if inside a '['..']' pair
int c;
while ((c = getChar()) != '/' || inCharSet) {
if (c == '\n' || c == EOF_CHAR) {
ungetChar(c);
throw parser.reportError("msg
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
return true;
} else {
continue;
}
}
c = getChar();
}
stringBufferTop = 0; // throw away the string in progress
this.string = null;
parser.addError("msg.XML.bad.form");
return false;
}
/**
*
*/
private boolean readEntity() throws IOException
{
int declTags = 1;
for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
addToString(c);
switch (c) {
case '<':
declTags++;
break;
case '>':
declTags--;
if (declTags == 0) return true;
break;
}
}
stringBufferTop = 0; // throw away the string in progress
this.string = null;
parser.addError("msg.XML.bad.form");
return false;
}
/**
*
*/
private boolean readPI() throws IOException
{
for (int c = getChar(); c != EOF_CHAR; c = getChar()) {
addToString(c);
if (c == '?' && peekChar() == '>') {
c = getChar(); // Skip >
addToString(c);
return true;
}
}
stringBufferTop = 0; // throw away the string in progress
this.string = null;
parser.addError("msg.XML.bad.form");
return false;
}
private String getStringFromBuffer()
{
return new String(stringBuffer, 0, stringBufferTop);
}
private void addToString(int c)
{
int N = stringBufferTop;
if (N == stringBuffer.length) {
char[] tmp = new char[stringBuffer.length * 2];
System.arraycopy(stringBuffer, 0, tmp, 0, N);
stringBuffer = tmp;
}
stringBuffer[N] = (char)c;
stringBufferTop = N + 1;
}
public int getTokenno() { return tokenno; }
protected void ungetChar(int c)
{
// cannot unread past across line boundary
if (ungetCursor != 0 && ungetBuffer[ungetCursor - 1] == '\n')
Kit.codeBug
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>();
ungetBuffer[ungetCursor++] = c;
}
private boolean matchChar(int test) throws IOException
{
int c = getChar();
if (c == test) {
return true;
} else {
ungetChar(c);
return false;
}
}
private int peekChar() throws IOException
{
int c = getChar();
ungetChar(c);
return c;
}
protected int getChar() throws IOException
{
if (ungetCursor != 0) {
--ungetCursor;
if (charno == -1) {
charno = getOffset();
}
return ungetBuffer[ungetCursor];
}
for(;;) {
int c;
if (sourceString != null) {
if (sourceCursor == sourceEnd) {
hitEOF = true;
if (charno == -1) {
charno = getOffset();
}
return EOF_CHAR;
}
c = sourceString.charAt(sourceCursor++);
} else {
if (sourceCursor == sourceEnd) {
if (!fillSourceBuffer()) {
hitEOF = true;
if (charno == -1) {
charno = getOffset();
}
return EOF_CHAR;
}
}
c = sourceBuffer[sourceCursor++];
}
if (lineEndChar >= 0) {
if (lineEndChar == '\r' && c == '\n') {
lineEndChar = '\n';
continue;
}
lineEndChar = -1;
lineStart = sourceCursor - 1;
lineno++;
}
if (c <= 127) {
if (c == '\n' || c == '\r') {
lineEndChar = c;
c = '\n';
}
} else {
if (isJSFormatChar(c)) {
continue;
}
if (ScriptRuntime.isJSLineTerminator(c)) {
lineEndChar = c;
c = '\n';
}
}
if (charno == -1) {
charno = getOffset();
}
return c;
}
}
private void skipLine() throws IOException
{
// skip to end of line
int c;
while ((c = getChar()) != EOF
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>_CHAR && c != '\n') { }
ungetChar(c);
}
final int getOffset()
{
return sourceCursor - lineStart - ungetCursor - 1;
}
final String getLine()
{
if (sourceString != null) {
// String case
int lineEnd = sourceCursor;
if (lineEndChar >= 0) {
--lineEnd;
} else {
for (; lineEnd != sourceEnd; ++lineEnd) {
int c = sourceString.charAt(lineEnd);
if (ScriptRuntime.isJSLineTerminator(c)) {
break;
}
}
}
return sourceString.substring(lineStart, lineEnd);
} else {
// Reader case
int lineLength = sourceCursor - lineStart;
if (lineEndChar >= 0) {
--lineLength;
} else {
// Read until the end of line
for (;; ++lineLength) {
int i = lineStart + lineLength;
if (i == sourceEnd) {
try {
if (!fillSourceBuffer()) { break; }
} catch (IOException ioe) {
// ignore it, we're already displaying an error...
break;
}
// i recalculuation as fillSourceBuffer can move saved
// line buffer and change lineStart
i = lineStart + lineLength;
}
int c = sourceBuffer[i];
if (ScriptRuntime.isJSLineTerminator(c)) {
break;
}
}
}
return new String(sourceBuffer, lineStart, lineLength);
}
}
private boolean fillSourceBuffer() throws IOException
{
if (sourceString != null) Kit.codeBug();
if (sourceEnd == sourceBuffer.length) {
if (lineStart != 0) {
System.arraycopy(sourceBuffer, lineStart, sourceBuffer, 0,
sourceEnd - lineStart);
sourceEnd -= lineStart;
sourceCursor -= lineStart;
lineStart = 0;
} else {
char[] tmp = new char[sourceBuffer.length * 2];
System.arraycopy(sourceBuffer, 0, tmp, 0, sourceEnd);
sourceBuffer = tmp;
}
}
int n = sourceReader.read(sourceBuffer, sourceEnd,
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
sourceBuffer.length - sourceEnd);
if (n < 0) {
return false;
}
sourceEnd += n;
return true;
}
/**
* Set the FileLevelJsDocBuilder on the TokenStream. The TokenStream passes
* the builder on to the JSDocInfoParser if it exists. Otherwise this method
* is a no-op.
* @param fileLevelJsDocBuilder
*/
public void setFileLevelJsDocBuilder(
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) {
}
// stuff other than whitespace since start of line
private boolean dirtyLine;
String regExpFlags;
private int pushbackToken;
private int tokenno;
// Set this to an inital non-null value so that the Parser has
// something to retrieve even if an error has occured and no
// string is found. Fosters one class of error, but saves lots of
// code.
private String string = "";
private double number;
private char[] stringBuffer = new char[128];
private int stringBufferTop;
private ObjToIntMap allStrings = new ObjToIntMap(50);
// Room to backtrace from to < on failed match of the last - in <!--
private final int[] ungetBuffer = new int[3];
private int ungetCursor;
private boolean hitEOF = false;
private int lineStart = 0;
private int lineno;
private int charno = -1;
private int lineEndChar = -1;
private String sourceString;
private Reader sourceReader;
private char[] sourceBuffer;
private int sourceEnd;
private int sourceCursor;
// for xml tokenizer
private boolean xmlIsAttribute;
private boolean xmlIsTagContent;
private int xmlOpenTagsCount;
private Parser parser;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>REGION_LENGTH + 1) / 2 + 1);
for (int n = 1; n < startLine; n++) {
int nextpos = js.indexOf('\n', pos);
if (nextpos == -1) {
break;
}
pos = nextpos + 1;
}
int end = pos;
int endLine = startLine;
for (int n = 0; n < SOURCE_EXCERPT_REGION_LENGTH; n++, endLine++) {
end = js.indexOf('\n', end);
if (end == -1) {
break;
}
end++;
}
if (lineNumber >= endLine) {
return null;
}
if (end == -1) {
int last = js.length() - 1;
if (js.charAt(last) == '\n') {
return
new SimpleRegion(startLine, endLine, js.substring(pos, last));
} else {
return new SimpleRegion(startLine, endLine, js.substring(pos));
}
} else {
return new SimpleRegion(startLine, endLine, js.substring(pos, end));
}
}
@Override
public String toString() {
return fileName;
}
public static SourceFile fromFile(String fileName, Charset c) {
return fromFile(new File(fileName), c);
}
public static SourceFile fromFile(String fileName) {
return fromFile(new File(fileName));
}
public static SourceFile fromFile(File file, Charset c) {
return new OnDisk(file, c);
}
public static SourceFile fromFile(File file) {
return new OnDisk(file);
}
public static SourceFile fromCode(String fileName, String code) {
return new Preloaded(fileName, code);
}
public static SourceFile fromCode(String fileName,
String originalPath, String code) {
return new Preloaded(fileName, originalPath, code);
}
public static SourceFile fromInputStream(String fileName, InputStream s)
throws IOException {
return fromCode(fileName,
CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8)));
}
public static SourceFile fromInputStream(String fileName,
String originalPath, InputStream s) throws
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> IOException {
return fromCode(fileName, originalPath,
CharStreams.toString(new InputStreamReader(s, Charsets.UTF_8)));
}
public static SourceFile fromReader(String fileName, Reader r)
throws IOException {
return fromCode(fileName, CharStreams.toString(r));
}
public static SourceFile fromGenerator(String fileName,
Generator generator) {
return new Generated(fileName, generator);
}
//////////////////////////////////////////////////////////////////////////////
// Implementations
/**
* A source file where the code has been preloaded.
*/
static class Preloaded extends SourceFile {
Preloaded(String fileName, String code) {
this(fileName, fileName, code);
}
Preloaded(String fileName, String originalPath, String code) {
super(fileName);
super.setOriginalPath(originalPath);
super.setCode(code);
}
}
/**
* A source file where the code will be dynamically generated
* from the injected interface.
*/
static class Generated extends SourceFile {
private final Generator generator;
// Not private, so that LazyInput can extend it.
Generated(String fileName, Generator generator) {
super(fileName);
this.generator = generator;
}
@Override
public synchronized String getCode() throws IOException {
String cachedCode = super.getCode();
if (cachedCode == null) {
cachedCode = generator.getCode();
super.setCode(cachedCode);
}
return cachedCode;
}
// Clear out the generated code when finished with a compile; we can
// regenerate it if we ever need it again.
@Override
public void clearCachedSource() {
super.setCode(null);
}
}
/**
* A source file where the code is only read into memory if absolutely
* necessary. We will try to delay loading the code into memory as long as
* possible.
*/
static class OnDisk extends SourceFile {
private final File file;
// This is stored as a String, but passed in and out as a Charset so that
// we can serialize the class.
// Default input file format for JSCompiler has always been UTF_8.
protected String inputCharset = Charsets.UTF_8.name();
OnDisk(File file, Charset c) {
this(file);
if (c != null) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> this.setCharset(c);
}
}
// No Charset provided?
OnDisk(File file) {
super(file.getPath());
this.file = file;
}
@Override
public synchronized String getCode() throws IOException {
String cachedCode = super.getCode();
if (cachedCode == null) {
cachedCode = Files.toString(file, this.getCharset());
super.setCode(cachedCode);
}
return cachedCode;
}
/**
* Gets a reader for the code in this source file.
*/
@Override
public Reader getCodeReader() throws IOException {
if (hasSourceInMemory()) {
return super.getCodeReader();
} else {
// If we haven't pulled the code into memory yet, don't.
return new FileReader(file);
}
}
// Flush the cached code after the compile; we can read it off disk
// if we need it again.
@Override
public void clearCachedSource() {
super.setCode(null);
}
/**
* Store the Charset specification as the string version of the name,
* rather than the Charset itself. This allows us to serialize the
* SourceFile class.
* @param c charset to use when reading the input.
*/
public void setCharset(Charset c) {
inputCharset = c.name();
}
/**
* Get the Charset specifying how we're supposed to read the file
* in off disk and into UTF-16. This is stored as a strong to allow
* SourceFile to be serialized.
* @return Charset object representing charset to use.
*/
public Charset getCharset() {
return Charset.forName(inputCharset);
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(String sourceName) {
this.sourceName = sourceName;
}
public final int getEncodedSourceStart() { return encodedSourceStart; }
public final int getEncodedSourceEnd() { return encodedSourceEnd; }
public final void setEncodedSourceBounds(int start, int end) {
this.encodedSourceStart = start;
this.encodedSourceEnd = end;
}
public final int getBaseLineno() { return baseLineno; }
public final void setBaseLineno(int lineno) {
// One time action
if (lineno < 0 || baseLineno >= 0) Kit.codeBug();
baseLineno = lineno;
}
public final int getEndLineno() { return endLineno; }
public final void setEndLineno(int lineno) {
// One time action
if (lineno < 0 || endLineno >= 0) Kit.codeBug();
endLineno = lineno;
}
public final int getFunctionCount() {
if (functions == null) { return 0; }
return functions.size();
}
public final FunctionNode getFunctionNode(int i) {
return (FunctionNode)functions.get(i);
}
public final int addFunction(FunctionNode fnNode) {
if (fnNode == null) Kit.codeBug();
if (functions == null) { functions = new ObjArray(); }
functions.add(fnNode);
return functions.size() - 1;
}
public final int getRegexpCount() {
if (regexps == null) { return 0; }
return regexps.size() / 2;
}
public final String getRegexpString(int index) {
return (String)regexps.get(index * 2);
}
public final String getRegexpFlags(int index) {
return (String)regexps.get(index * 2 + 1);
}
public final int addRegexp(String string, String flags) {
if (string == null) Kit.codeBug();
if (regexps == null) { regexps = new ObjArray(); }
regexps.add(string);
regexps.add(flags);
return regexps.size() / 2 - 1;
}
public final boolean hasParamOrVar
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(String name) {
return itsVariableNames.has(name);
}
public final int getParamOrVarIndex(String name) {
return itsVariableNames.get(name, -1);
}
public final String getParamOrVarName(int index) {
return (String)itsVariables.get(index);
}
public final int getParamCount() {
return varStart;
}
public final int getParamAndVarCount() {
return itsVariables.size();
}
public final String[] getParamAndVarNames() {
int N = itsVariables.size();
if (N == 0) {
return ScriptRuntime.emptyStrings;
}
String[] array = new String[N];
itsVariables.toArray(array);
return array;
}
public final boolean[] getParamAndVarConst() {
int N = itsVariables.size();
boolean[] array = new boolean[N];
for (int i = 0; i < N; i++)
if (itsConst.get(i) != null)
array[i] = true;
return array;
}
public final void addParam(String name) {
// Check addparam is not called after addLocal
if (varStart != itsVariables.size()) Kit.codeBug();
// Allow non-unique parameter names: use the last occurrence (parser
// will warn about dups)
int index = varStart++;
itsVariables.add(name);
itsConst.add(null);
itsVariableNames.put(name, index);
}
public static final int NO_DUPLICATE = 1;
public static final int DUPLICATE_VAR = 0;
public static final int DUPLICATE_PARAMETER = -1;
public static final int DUPLICATE_CONST = -2;
/**
* This function adds a variable to the set of var declarations for a
* function (or script). This returns an indicator of a duplicate that
* overrides a formal parameter (false if this dups a parameter).
* @param name variable name
* @return 1 if the name is not any form of duplicate, 0 if it duplicates a
* non-parameter, -1 if it duplicates a parameter and -2 if it duplicates a
* const.
*/
public final int
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> addVar(String name) {
int vIndex = itsVariableNames.get(name, -1);
if (vIndex != -1) {
// There's already a variable or parameter with this name.
if (vIndex >= varStart) {
Object v = itsConst.get(vIndex);
if (v != null)
return DUPLICATE_CONST;
else
return DUPLICATE_VAR;
} else
return DUPLICATE_PARAMETER;
}
int index = itsVariables.size();
itsVariables.add(name);
itsConst.add(null);
itsVariableNames.put(name, index);
return NO_DUPLICATE;
}
public final boolean addConst(String name) {
int vIndex = itsVariableNames.get(name, -1);
if (vIndex != -1) {
// There's already a variable or parameter with this name.
return false;
}
int index = itsVariables.size();
itsVariables.add(name);
itsConst.add(name);
itsVariableNames.put(name, index);
return true;
}
public final void removeParamOrVar(String name) {
int i = itsVariableNames.get(name, -1);
if (i != -1) {
itsVariables.remove(i);
itsVariableNames.remove(name);
ObjToIntMap.Iterator iter = itsVariableNames.newIterator();
for (iter.start(); !iter.done(); iter.next()) {
int v = iter.getValue();
if (v > i) {
iter.setValue(v - 1);
}
}
}
}
public final Object getCompilerData()
{
return compilerData;
}
public final void setCompilerData(Object data)
{
if (data == null) throw new IllegalArgumentException();
// Can only call once
if (compilerData != null) throw new IllegalStateException();
compilerData = data;
}
private int encodedSourceStart;
private int encodedSourceEnd;
private String sourceName;
private int baseLineno = -1;
private int endLineno = -1;
private ObjArray functions;
private ObjArray regexps;
// a list of the formal parameters and local variables
private ObjArray itsVariables
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.lineLengthThreshold = lineLengthThreshold <= 0 ? Integer.MAX_VALUE :
lineLengthThreshold;
this.createSrcMap = createSrcMap;
this.sourceMapDetailLevel = sourceMapDetailLevel;
this.mappings = createSrcMap ? new ArrayDeque<Mapping>() : null;
this.allMappings = createSrcMap ? new ArrayList<Mapping>() : null;
}
/**
* Maintains a mapping from a given node to the position
* in the source code at which its generated form was
* placed. This position is relative only to the current
* run of the CodeConsumer and will be normalized
* later on by the SourceMap.
*
* @see SourceMap
*/
private static class Mapping {
Node node;
FilePosition start;
FilePosition end;
}
/**
* Starts the source mapping for the given
* node at the current position.
*/
@Override
void startSourceMapping(Node node) {
Preconditions.checkState(sourceMapDetailLevel != null);
Preconditions.checkState(node != null);
if (createSrcMap
&& node.getProp(Node.SOURCENAME_PROP) != null
&& node.getLineno() > 0
&& sourceMapDetailLevel.apply(node)) {
int line = getCurrentLineIndex();
int index = getCurrentCharIndex();
Preconditions.checkState(line >= 0);
Mapping mapping = new Mapping();
mapping.node = node;
mapping.start = new FilePosition(line, index);
mappings.push(mapping);
allMappings.add(mapping);
}
}
/**
* Finishes the source mapping for the given
* node at the current position.
*/
@Override
void endSourceMapping(Node node) {
if (createSrcMap && !mappings.isEmpty() && mappings.peek().node == node) {
Mapping mapping = mappings.pop();
int line = getCurrentLineIndex();
int index = getCurrentCharIndex();
Preconditions.checkState(line >= 0);
mapping.end = new FilePosition(line, index);
}
}
/**
* Generates the source map from the given code consumer,
* appending the information it saved to the SourceMap
* object given.
*/
void generateSourceMap(SourceMap map){
if (create
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>SrcMap) {
for (Mapping mapping : allMappings) {
map.addMapping(mapping.node, mapping.start, mapping.end);
}
}
}
/**
* Reports to the code consumer that the given line has been cut at the
* given position (i.e. a \n has been inserted there). All mappings in
* the source maps after that position will be renormalized as needed.
*/
void reportLineCut(int lineIndex, int charIndex) {
if (createSrcMap) {
for (Mapping mapping : allMappings) {
mapping.start = convertPosition(mapping.start, lineIndex, charIndex);
if (mapping.end != null) {
mapping.end = convertPosition(mapping.end, lineIndex, charIndex);
}
}
}
}
/**
* Converts the given position by normalizing it against the insertion
* of a newline at the given line and character position.
*
* @param position The existing position before the newline was inserted.
* @param lineIndex The index of the line at which the newline was inserted.
* @param characterPosition The position on the line at which the newline
* was inserted.
*
* @return The normalized position.
*/
private FilePosition convertPosition(FilePosition position, int lineIndex,
int characterPosition) {
int originalLine = position.getLine();
int originalChar = position.getColumn();
if (originalLine == lineIndex && originalChar >= characterPosition) {
// If the position falls on the line itself, then normalize it
// if it falls at or after the place the newline was inserted.
return new FilePosition(
originalLine + 1, originalChar - characterPosition);
} else {
return position;
}
}
public String getCode() {
return code.toString();
}
@Override
char getLastChar() {
return (code.length() > 0) ? code.charAt(code.length() - 1) : '\0';
}
protected final int getCurrentCharIndex() {
return lineLength;
}
protected final int getCurrentLineIndex() {
return lineIndex;
}
}
static class PrettyCodePrinter
extends MappedCodePrinter {
// The number of characters after which we insert a line break in the code
static
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> final String INDENT = " ";
private int indent = 0;
/**
* @param lineLengthThreshold The length of a line after which we force
* a newline when possible.
* @param createSourceMap Whether to generate source map data.
* @param sourceMapDetailLevel A filter to control which nodes get mapped
* into the source map.
*/
private PrettyCodePrinter(
int lineLengthThreshold,
boolean createSourceMap,
SourceMap.DetailLevel sourceMapDetailLevel) {
super(lineLengthThreshold, createSourceMap, sourceMapDetailLevel);
}
/**
* Appends a string to the code, keeping track of the current line length.
*/
@Override
void append(String str) {
// For pretty printing: indent at the beginning of the line
if (lineLength == 0) {
for (int i = 0; i < indent; i++) {
code.append(INDENT);
lineLength += INDENT.length();
}
}
code.append(str);
lineLength += str.length();
}
/**
* Adds a newline to the code, resetting the line length and handling
* indenting for pretty printing.
*/
@Override
void startNewLine() {
if (lineLength > 0) {
code.append('\n');
lineIndex++;
lineLength = 0;
}
}
@Override
void maybeLineBreak() {
maybeCutLine();
}
/**
* This may start a new line if the current line is longer than the line
* length threshold.
*/
@Override
void maybeCutLine() {
if (lineLength > lineLengthThreshold) {
startNewLine();
}
}
@Override
void endLine() {
startNewLine();
}
@Override
void appendBlockStart() {
append(" {");
indent++;
}
@Override
void appendBlockEnd() {
endLine();
indent--;
append("}");
}
@Override
void listSeparator() {
add(", ");
maybeLineBreak();
}
@Override
void endFunction(boolean statementContext) {
super.endFunction(statementContext);
if (statementContext) {
startNewLine();
}
}
@Override
void beginCaseBody() {
super.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> being lines longer than the threshold. Since the output is going to be
// gzipped, it makes sense to try to make the newlines appear in similar
// contexts so that GZIP can encode them for 'free'.
//
// This version tries to break the lines at 'preferred' places, which are
// between the top-level forms. This works because top level forms tend to
// be more uniform than arbitary legal contexts. Better compression would
// probably require explicit modelling of the gzip algorithm.
private final boolean lineBreak;
private int lineStartPosition = 0;
private int preferredBreakPosition = 0;
/**
* @param lineBreak break the lines a bit more aggressively
* @param lineLengthThreshold The length of a line after which we force
* a newline when possible.
* @param createSrcMap Whether to gather source position
* mapping information when printing.
* @param sourceMapDetailLevel A filter to control which nodes get mapped into
* the source map.
*/
private CompactCodePrinter(boolean lineBreak, int lineLengthThreshold,
boolean createSrcMap, SourceMap.DetailLevel sourceMapDetailLevel) {
super(lineLengthThreshold, createSrcMap, sourceMapDetailLevel);
this.lineBreak = lineBreak;
}
/**
* Appends a string to the code, keeping track of the current line length.
*/
@Override
void append(String str) {
code.append(str);
lineLength += str.length();
}
/**
* Adds a newline to the code, resetting the line length.
*/
@Override
void startNewLine() {
if (lineLength > 0) {
code.append('\n');
lineLength = 0;
lineIndex++;
lineStartPosition = code.length();
}
}
@Override
void maybeLineBreak() {
if (lineBreak) {
if (sawFunction) {
startNewLine();
sawFunction = false;
}
}
// Since we are at a legal line break, can we upgrade the
// preferred break position? We prefer to break after a
// semicolon rather than before it.
int len = code.length();
if (preferredBreakPosition == len - 1) {
char ch = code.charAt
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(len - 1);
if (ch == ';') {
preferredBreakPosition = len;
}
}
maybeCutLine();
}
/**
* This may start a new line if the current line is longer than the line
* length threshold.
*/
@Override
void maybeCutLine() {
if (lineLength > lineLengthThreshold) {
// Use the preferred position provided it will break the line.
if (preferredBreakPosition > lineStartPosition &&
preferredBreakPosition < lineStartPosition + lineLength) {
int position = preferredBreakPosition;
code.insert(position, '\n');
reportLineCut(lineIndex, position - lineStartPosition);
lineIndex++;
lineLength -= (position - lineStartPosition);
lineStartPosition = position + 1;
} else {
startNewLine();
}
}
}
@Override
void notePreferredLineBreak() {
preferredBreakPosition = code.length();
}
}
static class Builder {
private final Node root;
private boolean prettyPrint = false;
private boolean lineBreak = false;
private boolean outputTypes = false;
private int lineLengthThreshold = DEFAULT_LINE_LENGTH_THRESHOLD;
private SourceMap sourceMap = null;
private SourceMap.DetailLevel sourceMapDetailLevel =
SourceMap.DetailLevel.ALL;
// Specify a charset to use when outputting source code. If null,
// then just output ASCII.
private Charset outputCharset = null;
private boolean tagAsStrict;
/**
* Sets the root node from which to generate the source code.
* @param node The root node.
*/
Builder(Node node) {
root = node;
}
/**
* Sets whether pretty printing should be used.
* @param prettyPrint If true, pretty printing will be used.
*/
Builder setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
return this;
}
/**
* Sets whether line breaking should be done automatically.
* @param lineBreak If true, line breaking is done automatically.
*/
Builder setLineBreak(boolean lineBreak) {
this.lineBreak = lineBreak;
return this;
}
/**
* Sets whether to output closure-style type annotations.
* @param outputTypes If true, outputs closure-style
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
private FlowScope caseNameOrGetProp(Node name, FlowScope blindScope,
boolean outcome) {
JSType type = getTypeIfRefinable(name, blindScope);
if (type != null) {
JSType restrictedType =
type.getRestrictedTypeGivenToBooleanOutcome(outcome);
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, name, restrictedType);
return informed;
}
return blindScope;
}
private FlowScope caseTypeOf(Node node, JSType type, String value,
boolean resultEqualsValue, FlowScope blindScope) {
JSType restrictedType =
getRestrictedByTypeOfResult(type, value, resultEqualsValue);
if (restrictedType == null) {
return blindScope;
}
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, node, restrictedType);
return informed;
}
private FlowScope caseInstanceOf(Node left, Node right, FlowScope blindScope,
boolean outcome) {
JSType leftType = getTypeIfRefinable(left, blindScope);
if (leftType == null) {
return blindScope;
}
JSType rightType = right.getJSType();
ObjectType targetType =
typeRegistry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE);
if (rightType instanceof FunctionType) {
targetType = (FunctionType) rightType;
}
Visitor<JSType> visitor;
if (outcome) {
visitor = new RestrictByTrueInstanceOfResultVisitor(targetType);
} else {
visitor = new RestrictByFalseInstanceOfResultVisitor(targetType);
}
JSType restrictedLeftType = leftType.visit(visitor);
if (restrictedLeftType != null && !restrictedLeftType.equals(leftType)) {
FlowScope informed = blindScope.createChildFlowScope();
declareNameInScope(informed, left, restrictedLeftType);
return informed;
}
return blindScope;
}
/**
* Given 'property in object', ensures that the object has the property in the
* informed scope by defining it as a qualified name if the object type lacks
* the property and it's not in the blind scope.
* @param object The node of the right-
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> functions that are assigned to variables or
// properties
// e.g. goog.string.htmlEscape = function(str) {
// }
// get the function name and see if it's empty
Node functionNameNode = n.getFirstChild();
String functionName = functionNameNode.getString();
if (functionName.length() == 0) {
if (parent.getType() == Token.ASSIGN) {
// this is an assignment to a property, generally either a
// static function or a prototype function
// e.g. goog.string.htmlEscape = function() { } or
// goog.structs.Map.prototype.getCount = function() { }
Node lhs = parent.getFirstChild();
String name = namer.getName(lhs);
namer.setFunctionName(name, n);
} else if (parent.getType() == Token.NAME) {
// this is an assignment to a variable
// e.g. var handler = function() {}
String name = namer.getName(parent);
namer.setFunctionName(name, n);
}
}
break;
case Token.ASSIGN:
// this handles functions that are assigned to a prototype through
// an object literal
// e.g. BuzzApp.prototype = {
// Start : function() { }
// }
Node lhs = n.getFirstChild();
Node rhs = lhs.getNext();
if (rhs.getType() == Token.OBJECTLIT) {
nameObjectLiteralMethods(rhs, namer.getName(lhs));
}
}
}
private void nameObjectLiteralMethods(Node objectLiteral, String context) {
for (Node keyNode = objectLiteral.getFirstChild();
keyNode != null;
keyNode = keyNode.getNext()) {
Node valueNode = keyNode.getFirstChild();
// Object literal keys may be STRING, GET, SET or NUMBER. Numbers are
// skipped because name tokens may not start with a number. Get and Set
// are skipped because they can not be named.
if (keyNode.getType() == Token.STRING) {
// concatenate the context and key name to get a new qualified name.
String name = namer.getCombinedName(context, namer.getName(keyNode));
int type = valueNode.getType();
if (type ==
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2007 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.rhino.Node;
import java.util.regex.Pattern;
/**
* This describes the Google-specific JavaScript coding conventions.
* Within Google, variable names are semantically significant.
*
*/
public class GoogleCodingConvention extends ClosureCodingConvention {
private static final long serialVersionUID = 1L;
private static final String OPTIONAL_ARG_PREFIX = "opt_";
private static final String VAR_ARGS_NAME = "var_args";
private static final Pattern ENUM_KEY_PATTERN =
Pattern.compile("[A-Z0-9][A-Z0-9_]*");
/**
* {@inheritDoc}
*
* <p>This enforces the Google const name convention, that the first character
* after the last $ must be an upper-case letter and all subsequent letters
* must be upper case. The name must be at least 2 characters long.
*
* <p>Examples:
* <pre>
* aaa Not constant - lower-case letters in the name
* A Not constant - too short
* goog$A Constant - letters after the $ are upper-case.
* AA17 Constant - digits can appear after the first letter
* goog$7A Not constant - first character after the $ must be
* upper case.
* $A Constant - doesn't have to be anything in front of the $
* </pre>
*/
@Override
public boolean isConstant(String name) {
if (name.length() <= 1)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
return false;
}
// In compiled code, '$' is often a namespace delimiter. To allow inlining
// of namespaced constants, we strip off any namespaces here.
int pos = name.lastIndexOf('$');
if (pos >= 0) {
name = name.substring(pos + 1);
if (name.length() == 0) {
return false;
}
}
return isConstantKey(name);
}
@Override
public boolean isConstantKey(String name) {
if (name.isEmpty() || !Character.isUpperCase(name.charAt(0))) {
return false;
}
// hack way of checking that there aren't any lower-case letters
return name.toUpperCase().equals(name);
}
/**
* {@inheritDoc}
*
* <p>This enforces Google's convention about enum key names. They must match
* the regular expression {@code [A-Z0-9][A-Z0-9_]*}.
*
* <p>Examples:
* <ul>
* <li>A</li>
* <li>213</li>
* <li>FOO_BAR</li>
* </ul>
*/
@Override
public boolean isValidEnumKey(String key) {
return ENUM_KEY_PATTERN.matcher(key).matches();
}
/**
* {@inheritDoc}
*
* <p>In Google code, parameter names beginning with {@code opt_} are
* treated as optional arguments.
*/
@Override
public boolean isOptionalParameter(Node parameter) {
return parameter.getString().startsWith(OPTIONAL_ARG_PREFIX);
}
@Override
public boolean isVarArgsParameter(Node parameter) {
return VAR_ARGS_NAME.equals(parameter.getString());
}
/**
* {@inheritDoc}
*
* <p>In Google code, any global name starting with an underscore is
* considered exported.
*/
@Override
public boolean isExported(String name, boolean local) {
return super.isExported(name, local) ||
(!local && name.startsWith("_"));
}
/**
* {@inheritDoc}
*
* <p>In Google code, private names end with an underscore, and exported
* names are never considered private (see {@link
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Token.STRING, key.getType());
assertEquals(3, key.getLineno());
assertEquals(10, key.getCharno());
Node value = key.getFirstChild();
assertEquals(Token.NUMBER, value.getType());
assertEquals(3, value.getLineno());
assertEquals(12, value.getCharno());
key = key.getNext();
assertEquals(Token.STRING, key.getType());
assertEquals(4, key.getLineno());
assertEquals(1, key.getCharno());
value = key.getFirstChild();
assertEquals(Token.NUMBER, value.getType());
assertEquals(4, value.getLineno());
assertEquals(4, value.getCharno());
}
public void testLinenoCharnoAdd() throws Exception {
testLinenoCharnoBinop("+");
}
public void testLinenoCharnoSub() throws Exception {
testLinenoCharnoBinop("-");
}
public void testLinenoCharnoMul() throws Exception {
testLinenoCharnoBinop("*");
}
public void testLinenoCharnoDiv() throws Exception {
testLinenoCharnoBinop("/");
}
public void testLinenoCharnoMod() throws Exception {
testLinenoCharnoBinop("%");
}
public void testLinenoCharnoShift() throws Exception {
testLinenoCharnoBinop("<<");
}
public void testLinenoCharnoBinaryAnd() throws Exception {
testLinenoCharnoBinop("&");
}
public void testLinenoCharnoAnd() throws Exception {
testLinenoCharnoBinop("&&");
}
public void testLinenoCharnoBinaryOr() throws Exception {
testLinenoCharnoBinop("|");
}
public void testLinenoCharnoOr() throws Exception {
testLinenoCharnoBinop("||");
}
public void testLinenoCharnoLt() throws Exception {
testLinenoCharnoBinop("<");
}
public void testLinenoCharnoLe() throws Exception {
testLinenoCharnoBinop("<=");
}
public void testLinenoCharnoGt() throws Exception {
testLinenoCharnoBinop(">");
}
public void testLinenoCharnoGe() throws Exception {
testLinenoCharnoBinop(">=");
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
}
private void testLinenoCharnoBinop(String binop) {
Node op = parse("var a = 89 " + binop + " 76").getFirstChild().
getFirstChild().getFirstChild();
assertEquals(1, op.getLineno());
assertEquals(11, op.getCharno());
}
public void testJSDocAttachment1() {
Node varNode = parse("/** @type number */var a;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
JSDocInfo info = varNode.getJSDocInfo();
assertNotNull(info);
assertTypeEquals(NUMBER_TYPE, info.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment2() {
Node varNode = parse("/** @type number */var a,b;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
JSDocInfo info = varNode.getJSDocInfo();
assertNotNull(info);
assertTypeEquals(NUMBER_TYPE, info.getType());
// First NAME
Node nameNode1 = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode1.getType());
assertNull(nameNode1.getJSDocInfo());
// Second NAME
Node nameNode2 = nameNode1.getNext();
assertEquals(Token.NAME, nameNode2.getType());
assertNull(nameNode2.getJSDocInfo());
}
public void testJSDocAttachment3() {
Node assignNode = parse(
"/** @type number */goog.FOO = 5;").getFirstChild().getFirstChild();
// ASSIGN
assertEquals(Token.ASSIGN, assignNode.getType());
JSDocInfo info = assignNode.getJSDocInfo();
assertNotNull(info);
assertTypeEquals(NUMBER_TYPE, info.getType());
}
public void testJSDocAttachment4() {
Node varNode = parse(
"var a, /** @define {number} */b = 5;").getFirstChild();
// ASSIGN
assertEquals(Token.VAR, varNode.getType());
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> assertNull(varNode.getJSDocInfo());
// a
Node a = varNode.getFirstChild();
assertNull(a.getJSDocInfo());
// b
Node b = a.getNext();
JSDocInfo info = b.getJSDocInfo();
assertNotNull(info);
assertTrue(info.isDefine());
assertTypeEquals(NUMBER_TYPE, info.getType());
}
public void testJSDocAttachment5() {
Node varNode = parse(
"var /** @type number */a, /** @define {number} */b = 5;")
.getFirstChild();
// ASSIGN
assertEquals(Token.VAR, varNode.getType());
assertNull(varNode.getJSDocInfo());
// a
Node a = varNode.getFirstChild();
assertNotNull(a.getJSDocInfo());
JSDocInfo info = a.getJSDocInfo();
assertNotNull(info);
assertFalse(info.isDefine());
assertTypeEquals(NUMBER_TYPE, info.getType());
// b
Node b = a.getNext();
info = b.getJSDocInfo();
assertNotNull(info);
assertTrue(info.isDefine());
assertTypeEquals(NUMBER_TYPE, info.getType());
}
/**
* Tests that a JSDoc comment in an unexpected place of the code does not
* propagate to following code due to {@link JSDocInfo} aggregation.
*/
public void testJSDocAttachment6() throws Exception {
Node functionNode = parse(
"var a = /** @param {number} index */5;" +
"/** @return boolean */function f(index){}")
.getFirstChild().getNext();
assertEquals(Token.FUNCTION, functionNode.getType());
JSDocInfo info = functionNode.getJSDocInfo();
assertNotNull(info);
assertFalse(info.hasParameter("index"));
assertTrue(info.hasReturnType());
assertTypeEquals(UNKNOWN_TYPE, info.getReturnType());
}
public void testJSDocAttachment7() {
Node varNode = parse("/** */var a;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment8() {
Node varNode = parse("/** x */var a;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment9() {
Node varNode = parse("/** \n x */var a;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment10() {
Node varNode = parse("/** x\n */var a;").getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment11() {
Node varNode =
parse("/** @type {{x : number, 'y' : string, z}} */var a;")
.getFirstChild();
// VAR
assertEquals(Token.VAR, varNode.getType());
JSDocInfo info = varNode.getJSDocInfo();
assertNotNull(info);
assertTypeEquals(createRecordTypeBuilder().
addProperty("x", NUMBER_TYPE, null).
addProperty("y", STRING_TYPE, null).
addProperty("z", UNKNOWN_TYPE, null).
build(),
info.getType());
// NAME
Node nameNode = varNode.getFirstChild();
assertEquals(Token.NAME, nameNode.getType());
assertNull(nameNode.getJSDocInfo());
}
public void testJSDocAttachment12() {
Node varNode =
parse("var a = {/** @type {Object} */ b: c};")
.getFirstChild();
Node objectLitNode = varNode.getFirstChild().getFirstChild();
assertEquals(Token.OBJECTLIT, objectLit
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Node<N, E> dNode2 = getNodeOrFail(n2);
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2) {
return outEdge;
}
}
for (DiGraphEdge<N, E> outEdge : dNode2.getOutEdges()) {
if (outEdge.getDestination() == dNode1) {
return outEdge;
}
}
return null;
}
@Override
public GraphNode<N, E> createNode(N value) {
return createDirectedGraphNode(value);
}
@Override
public List<DiGraphEdge<N, E>> getDirectedGraphEdges(N n1, N n2) {
DiGraphNode<N, E> dNode1 = getNodeOrFail(n1);
DiGraphNode<N, E> dNode2 = getNodeOrFail(n2);
List<DiGraphEdge<N, E>> edges = Lists.newArrayList();
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2) {
edges.add(outEdge);
}
}
return edges;
}
@Override
public boolean isConnectedInDirection(N n1, N n2) {
return isConnectedInDirection(n1, Predicates.<E>alwaysTrue(), n2);
}
@Override
public boolean isConnectedInDirection(N n1, E edgeValue, N n2) {
return isConnectedInDirection(n1, Predicates.equalTo(edgeValue), n2);
}
private boolean isConnectedInDirection(N n1, Predicate<E> edgeMatcher, N n2) {
// Verify the nodes.
DiGraphNode<N, E> dNode1 = getNodeOrFail(n1);
DiGraphNode<N, E> dNode2 = getNodeOrFail(n2);
for (DiGraphEdge<N, E> outEdge : dNode1.getOutEdges()) {
if (outEdge.getDestination() == dNode2 &&
edgeMatcher.apply(outEdge.getValue())) {
return true;
}
}
return false;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
}
@Override
public boolean isDirected() {
return true;
}
@Override
public Collection<GraphNode<N, E>> getNodes() {
return Collections.<GraphNode<N, E>>unmodifiableCollection(nodes.values());
}
@Override
public List<GraphNode<N, E>> getNeighborNodes(N value) {
DiGraphNode<N, E> node = getDirectedGraphNode(value);
return getNeighborNodes(node);
}
public List<GraphNode<N, E>> getNeighborNodes(DiGraphNode<N, E> node) {
List<GraphNode<N, E>> result = Lists.newArrayList();
for (Iterator<GraphNode<N, E>> i =
((LinkedDirectedGraphNode<N, E>) node).neighborIterator();i.hasNext();) {
result.add(i.next());
}
return result;
}
@Override
public Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value) {
LinkedDirectedGraphNode<N, E> node = nodes.get(value);
Preconditions.checkNotNull(node);
return node.neighborIterator();
}
@Override
public List<GraphEdge<N, E>> getEdges() {
List<GraphEdge<N, E>> result = Lists.newArrayList();
for (DiGraphNode<N, E> node : nodes.values()) {
for (DiGraphEdge<N, E> edge : node.getOutEdges()) {
result.add(edge);
}
}
return Collections.unmodifiableList(result);
}
@Override
public int getNodeDegree(N value) {
DiGraphNode<N, E> node = getNodeOrFail(value);
return node.getInEdges().size() + node.getOutEdges().size();
}
/**
* A directed graph node that stores outgoing edges and incoming edges as an
* list within the node itself.
*/
static class LinkedDirectedGraphNode<N, E> implements DiGraphNode<N, E>,
GraphvizNode {
List<DiGraphEdge<N, E>> inEdgeList = Lists.newArrayList();
List<DiGraphEdge<N, E>> outEdgeList =
Lists.newArrayList();
protected final N value;
/**
* Constructor
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
*
* @param nodeValue Node's value.
*/
LinkedDirectedGraphNode(N nodeValue) {
this.value = nodeValue;
}
@Override
public N getValue() {
return value;
}
@Override
public <A extends Annotation> A getAnnotation() {
throw new UnsupportedOperationException(
"Graph initialized with node annotations turned off");
}
@Override
public void setAnnotation(Annotation data) {
throw new UnsupportedOperationException(
"Graph initialized with node annotations turned off");
}
@Override
public String getColor() {
return "white";
}
@Override
public String getId() {
return "LDN" + hashCode();
}
@Override
public String getLabel() {
return value != null ? value.toString() : "null";
}
@Override
public String toString() {
return getLabel();
}
@Override
public List<DiGraphEdge<N, E>> getInEdges() {
return inEdgeList;
}
@Override
public List<DiGraphEdge<N, E>> getOutEdges() {
return outEdgeList;
}
private Iterator<GraphNode<N, E>> neighborIterator() {
return new NeighborIterator();
}
private class NeighborIterator implements Iterator<GraphNode<N, E>> {
private final Iterator<DiGraphEdge<N, E>> in = inEdgeList.iterator();
private final Iterator<DiGraphEdge<N, E>> out = outEdgeList.iterator();
@Override
public boolean hasNext() {
return in.hasNext() || out.hasNext();
}
@Override
public GraphNode<N, E> next() {
boolean isOut = !in.hasNext();
Iterator<DiGraphEdge<N, E>> curIterator = isOut ? out : in;
DiGraphEdge<N, E> s = curIterator.next();
return isOut ? s.getDestination() : s.getSource();
}
@Override
public void remove() {
throw new UnsupportedOperationException("Remove not supported.");
}
}
}
/**
* A directed graph node with annotations.
*/
static class AnnotatedLinkedDirectedGraphNode<N, E>
extends LinkedDirectedGraphNode<N, E> {
protected Annotation annotation;
/**
* @
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>param nodeValue Node's value.
*/
AnnotatedLinkedDirectedGraphNode(N nodeValue) {
super(nodeValue);
}
@SuppressWarnings("unchecked")
@Override
public <A extends Annotation> A getAnnotation() {
return (A) annotation;
}
@Override
public void setAnnotation(Annotation data) {
annotation = data;
}
}
/**
* A directed graph edge that stores the source and destination nodes at each
* edge.
*/
static class LinkedDirectedGraphEdge<N, E> implements DiGraphEdge<N, E>,
GraphvizEdge {
private DiGraphNode<N, E> sourceNode;
private DiGraphNode<N, E> destNode;
protected final E value;
/**
* Constructor.
*
* @param edgeValue Edge Value.
*/
LinkedDirectedGraphEdge(DiGraphNode<N, E> sourceNode,
E edgeValue, DiGraphNode<N, E> destNode) {
this.value = edgeValue;
this.sourceNode = sourceNode;
this.destNode = destNode;
}
@Override
public DiGraphNode<N, E> getSource() {
return sourceNode;
}
@Override
public DiGraphNode<N, E> getDestination() {
return destNode;
}
@Override
public void setDestination(DiGraphNode<N, E> node) {
destNode = node;
}
@Override
public void setSource(DiGraphNode<N, E> node) {
sourceNode = node;
}
@Override
public E getValue() {
return value;
}
@Override
public <A extends Annotation> A getAnnotation() {
throw new UnsupportedOperationException(
"Graph initialized with edge annotations turned off");
}
@Override
public void setAnnotation(Annotation data) {
throw new UnsupportedOperationException(
"Graph initialized with edge annotations turned off");
}
@Override
public String getColor() {
return "black";
}
@Override
public String getLabel() {
return value != null ? value.toString() : "null";
}
@Override
public String getNode1Id() {
return ((LinkedDirectedGraphNode<N, E>) sourceNode).getId();
}
@Override
public String getNode
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>2Id() {
return ((LinkedDirectedGraphNode<N, E>) destNode).getId();
}
@Override
public String toString() {
return sourceNode.toString() + " -> " + destNode.toString();
}
@Override
public GraphNode<N, E> getNodeA() {
return sourceNode;
}
@Override
public GraphNode<N, E> getNodeB() {
return destNode;
}
}
/**
* A directed graph edge that stores the source and destination nodes at each
* edge.
*/
static class AnnotatedLinkedDirectedGraphEdge<N, E>
extends LinkedDirectedGraphEdge<N, E> {
protected Annotation annotation;
/**
* Constructor.
*
* @param edgeValue Edge Value.
*/
AnnotatedLinkedDirectedGraphEdge(DiGraphNode<N, E> sourceNode,
E edgeValue, DiGraphNode<N, E> destNode) {
super(sourceNode, edgeValue, destNode);
}
@SuppressWarnings("unchecked")
@Override
public <A extends Annotation> A getAnnotation() {
return (A) annotation;
}
@Override
public void setAnnotation(Annotation data) {
annotation = data;
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
implements NodeTraversal.Callback {
private final CodingConvention convention;
PrepareAnnotations(AbstractCompiler compiler) {
this.convention = compiler.getCodingConvention();
}
@Override
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.OBJECTLIT) {
normalizeObjectLiteralAnnotations(n);
}
return true;
}
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
switch (n.getType()) {
case Token.CALL:
annotateCalls(n);
break;
case Token.FUNCTION:
annotateFunctions(n, parent);
annotateDispatchers(n, parent);
break;
}
}
private void normalizeObjectLiteralAnnotations(Node objlit) {
Preconditions.checkState(objlit.getType() == Token.OBJECTLIT);
for (Node key = objlit.getFirstChild();
key != null; key = key.getNext()) {
Node value = key.getFirstChild();
normalizeObjectLiteralKeyAnnotations(objlit, key, value);
}
}
/**
* There are two types of calls we are interested in calls without explicit
* "this" values (what we are call "free" calls) and direct call to eval.
*/
private void annotateCalls(Node n) {
Preconditions.checkState(n.getType() == Token.CALL);
// Keep track of of the "this" context of a call. A call without an
// explicit "this" is a free call.
Node first = n.getFirstChild();
if (!NodeUtil.isGet(first)) {
n.putBooleanProp(Node.FREE_CALL, true);
}
// Keep track of the context in which eval is called. It is important
// to distinguish between "(0, eval)()" and "eval()".
if (first.getType() == Token.NAME &&
"eval".equals(first.getString())) {
first.putBooleanProp(Node.DIRECT_EVAL, true);
}
}
/**
* Translate dispatcher info into the property expected node.
*/
private void annotateDispatchers(Node n, Node parent) {
Preconditions.checkState(n.getType() == Token.FUNCTION);
if (parent.getJSDocInfo() != null
&&
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> parent.getJSDocInfo().isJavaDispatch()) {
if (parent.getType() == Token.ASSIGN) {
Preconditions.checkState(parent.getLastChild() == n);
n.putBooleanProp(Node.IS_DISPATCHER, true);
}
}
}
/**
* In the AST that Rhino gives us, it needs to make a distinction
* between jsdoc on the object literal node and jsdoc on the object literal
* value. For example,
* <pre>
* var x = {
* / JSDOC /
* a: 'b',
* c: / JSDOC / 'd'
* };
* </pre>
*
* But in few narrow cases (in particular, function literals), it's
* a lot easier for us if the doc is attached to the value.
*/
private void normalizeObjectLiteralKeyAnnotations(
Node objlit, Node key, Node value) {
Preconditions.checkState(objlit.getType() == Token.OBJECTLIT);
if (key.getJSDocInfo() != null &&
value.getType() == Token.FUNCTION) {
value.setJSDocInfo(key.getJSDocInfo());
}
}
/**
* Annotate optional and var_arg function parameters.
*/
private void annotateFunctions(Node n, Node parent) {
JSDocInfo fnInfo = NodeUtil.getFunctionInfo(n);
// Compute which function parameters are optional and
// which are var_args.
Node args = n.getFirstChild().getNext();
for (Node arg = args.getFirstChild();
arg != null;
arg = arg.getNext()) {
String argName = arg.getString();
JSTypeExpression typeExpr = fnInfo == null ?
null : fnInfo.getParameterType(argName);
if (convention.isOptionalParameter(arg) ||
typeExpr != null && typeExpr.isOptionalArg()) {
arg.putBooleanProp(Node.IS_OPTIONAL_PARAM, true);
}
if (convention.isVarArgsParameter(arg) ||
typeExpr != null && typeExpr.isVarArgs()) {
arg.putBooleanProp(Node.IS_VAR_ARGS_PARAM, true);
}
}
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> warning message.
* @param ownerType The type of the owner of the property, for use
* in the warning message.
*/
void expectCanOverride(NodeTraversal t, Node n, JSType overridingType,
JSType hiddenType, String propertyName, JSType ownerType) {
if (!overridingType.canAssignTo(hiddenType)) {
registerMismatch(overridingType, hiddenType);
if (shouldReport) {
compiler.report(
t.makeError(n, HIDDEN_PROPERTY_MISMATCH,
propertyName, ownerType.toString(),
hiddenType.toString(), overridingType.toString()));
}
}
}
/**
* Expect that the first type is the direct superclass of the second type.
*
* @param t The node traversal.
* @param n The node where warnings should point to.
* @param superObject The expected super instance type.
* @param subObject The sub instance type.
*/
void expectSuperType(NodeTraversal t, Node n, ObjectType superObject,
ObjectType subObject) {
FunctionType subCtor = subObject.getConstructor();
ObjectType declaredSuper =
subObject.getImplicitPrototype().getImplicitPrototype();
if (!declaredSuper.equals(superObject)) {
if (declaredSuper.equals(getNativeType(OBJECT_TYPE))) {
if (shouldReport) {
compiler.report(
t.makeError(n, MISSING_EXTENDS_TAG_WARNING,
subObject.toString()));
}
registerMismatch(superObject, declaredSuper);
} else {
mismatch(t.getSourceName(), n,
"mismatch in declaration of superclass type",
superObject, declaredSuper);
}
// Correct the super type.
if (!subCtor.hasCachedValues()) {
subCtor.setPrototypeBasedOn(superObject);
}
}
}
/**
* Expect that the first type can be cast to the second type. The first type
* should be either a subtype or supertype of the second.
*
* @param t The node traversal.
* @param n The node where warnings should point.
* @param type The type being cast from.
* @param castType The type being cast to.
*/
void expectCanCast(NodeTraversal t, Node n, JSType type, JSType cast
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Type) {
castType = castType.restrictByNotNullOrUndefined();
type = type.restrictByNotNullOrUndefined();
if (!type.canAssignTo(castType) && !castType.canAssignTo(type)) {
if (shouldReport) {
compiler.report(
t.makeError(n, INVALID_CAST,
castType.toString(), type.toString()));
}
registerMismatch(type, castType);
}
}
/**
* Expect that the given variable has not been declared with a type.
*
* @param sourceName The name of the source file we're in.
* @param n The node where warnings should point to.
* @param parent The parent of {@code n}.
* @param var The variable that we're checking.
* @param variableName The name of the variable.
* @param newType The type being applied to the variable. Mostly just here
* for the benefit of the warning.
*/
void expectUndeclaredVariable(String sourceName, Node n, Node parent, Var var,
String variableName, JSType newType) {
boolean allowDupe = false;
if (n.getType() == Token.GETPROP ||
NodeUtil.isObjectLitKey(n, parent)) {
JSDocInfo info = n.getJSDocInfo();
if (info == null) {
info = parent.getJSDocInfo();
}
allowDupe =
info != null && info.getSuppressions().contains("duplicate");
}
JSType varType = var.getType();
// Only report duplicate declarations that have types. Other duplicates
// will be reported by the syntactic scope creator later in the
// compilation process.
if (varType != null &&
varType != typeRegistry.getNativeType(UNKNOWN_TYPE) &&
newType != null &&
newType != typeRegistry.getNativeType(UNKNOWN_TYPE)) {
// If there are two typed declarations of the same variable, that
// is an error and the second declaration is ignored, except in the
// case of native types. A null input type means that the declaration
// was made in TypedScopeCreator#createInitialScope and is a
// native type.
if (var.input == null) {
n.setJSType(varType);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> if (parent.getType() == Token.VAR) {
if (n.getFirstChild() != null) {
n.getFirstChild().setJSType(varType);
}
} else {
Preconditions.checkState(parent.getType() == Token.FUNCTION);
parent.setJSType(varType);
}
} else {
// Always warn about duplicates if the overridden type does not
// match the original type.
//
// If the types match, suppress the warning iff there was a @suppress
// tag, or if the original declaration was a stub.
if (!(allowDupe ||
var.getParentNode().getType() == Token.EXPR_RESULT) ||
!newType.equals(varType)) {
if (shouldReport) {
compiler.report(
JSError.make(sourceName, n, DUP_VAR_DECLARATION,
variableName, newType.toString(), var.getInputName(),
String.valueOf(var.nameNode.getLineno()),
varType.toString()));
}
}
}
}
}
/**
* Expect that all properties on interfaces that this type implements are
* implemented and correctly typed.
*/
void expectAllInterfaceProperties(NodeTraversal t, Node n,
FunctionType type) {
ObjectType instance = type.getInstanceType();
for (ObjectType implemented : type.getAllImplementedInterfaces()) {
if (implemented.getImplicitPrototype() != null) {
for (String prop :
implemented.getImplicitPrototype().getOwnPropertyNames()) {
expectInterfaceProperty(t, n, instance, implemented, prop);
}
}
}
}
/**
* Expect that the peroperty in an interface that this type implements is
* implemented and correctly typed.
*/
private void expectInterfaceProperty(NodeTraversal t, Node n,
ObjectType instance, ObjectType implementedInterface, String prop) {
if (!instance.hasProperty(prop)) {
// Not implemented
String sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
sourceName = sourceName == null ? "" : sourceName;
if (shouldReport) {
compiler.report(JSError.make(sourceName, n,
INTERFACE_METHOD_NOT_IMPLEMENTED,
prop, implementedInterface.toString(), instance.toString()));
}
registerMismatch(instance, implemented
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Interface);
} else {
JSType found = instance.getPropertyType(prop);
JSType required
= implementedInterface.getImplicitPrototype().getPropertyType(prop);
found = found.restrictByNotNullOrUndefined();
required = required.restrictByNotNullOrUndefined();
if (!found.canAssignTo(required)) {
// Implemented, but not correctly typed
if (shouldReport) {
FunctionType constructor
= implementedInterface.toObjectType().getConstructor();
compiler.report(t.makeError(n,
HIDDEN_INTERFACE_PROPERTY_MISMATCH, prop,
constructor.getTopMostDefiningType(prop).toString(),
required.toString(), found.toString()));
}
registerMismatch(found, required);
}
}
}
/**
* Report a type mismatch
*/
private void mismatch(NodeTraversal t, Node n,
String msg, JSType found, JSType required) {
mismatch(t.getSourceName(), n, msg, found, required);
}
private void mismatch(NodeTraversal t, Node n,
String msg, JSType found, JSTypeNative required) {
mismatch(t, n, msg, found, getNativeType(required));
}
private void mismatch(String sourceName, Node n,
String msg, JSType found, JSType required) {
registerMismatch(found, required);
if (shouldReport) {
compiler.report(
JSError.make(sourceName, n, TYPE_MISMATCH_WARNING,
formatFoundRequired(msg, found, required)));
}
}
private void registerMismatch(JSType found, JSType required) {
// Don't register a mismatch for differences in null or undefined or if the
// code didn't downcast.
found = found.restrictByNotNullOrUndefined();
required = required.restrictByNotNullOrUndefined();
if (found.canAssignTo(required) || required.canAssignTo(found)) {
return;
}
mismatches.add(new TypeMismatch(found, required));
if (found instanceof FunctionType &&
required instanceof FunctionType) {
FunctionType fnTypeA = ((FunctionType) found);
FunctionType fnTypeB = ((FunctionType) required);
Iterator<Node> paramItA = fnTypeA.getParameters().iterator();
Iterator<Node> paramItB = fnTypeB
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.getParameters().iterator();
while (paramItA.hasNext() && paramItB.hasNext()) {
registerIfMismatch(paramItA.next().getJSType(),
paramItB.next().getJSType());
}
registerIfMismatch(fnTypeA.getReturnType(), fnTypeB.getReturnType());
}
}
private void registerIfMismatch(JSType found, JSType required) {
if (found != null && required != null &&
!found.canAssignTo(required)) {
registerMismatch(found, required);
}
}
/**
* Formats a found/required error message.
*/
private String formatFoundRequired(String description, JSType found,
JSType required) {
return MessageFormat.format(FOUND_REQUIRED, description, found, required);
}
/**
* Given a node, get a human-readable name for the type of that node so
* that will be easy for the programmer to find the original declaration.
*
* For example, if SubFoo's property "bar" might have the human-readable
* name "Foo.prototype.bar".
*
* @param n The node.
* @param dereference If true, the type of the node will be dereferenced
* to an Object type, if possible.
*/
String getReadableJSTypeName(Node n, boolean dereference) {
// If we're analyzing a GETPROP, the property may be inherited by the
// prototype chain. So climb the prototype chain and find out where
// the property was originally defined.
if (n.getType() == Token.GETPROP) {
ObjectType objectType = getJSType(n.getFirstChild()).dereference();
if (objectType != null) {
String propName = n.getLastChild().getString();
while (objectType != null && !objectType.hasOwnProperty(propName)) {
objectType = objectType.getImplicitPrototype();
}
// Don't show complex function names or anonymous types.
// Instead, try to get a human-readable type name.
if (objectType != null &&
(objectType.getConstructor() != null ||
objectType.isFunctionPrototypeType())) {
return objectType.toString() + "." + propName;
}
}
}
JSType type = getJSType(n);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
if (dereference) {
ObjectType dereferenced = type.dereference();
if (dereferenced != null) {
type = dereferenced;
}
}
String qualifiedName = n.getQualifiedName();
if (type.isFunctionPrototypeType() ||
(type.toObjectType() != null &&
type.toObjectType().getConstructor() != null)) {
return type.toString();
} else if (qualifiedName != null) {
return qualifiedName;
} else if (type instanceof FunctionType) {
// Don't show complex function names.
return "function";
} else {
return type.toString();
}
}
/**
* This method gets the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(user): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
private JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
/**
* Signals that the first type and the second type have been
* used interchangeably.
*
* Type-based optimizations should take this into account
* so that they don't wreck code with type warnings.
*/
static class TypeMismatch {
final JSType typeA;
final JSType typeB;
/**
* It's the responsibility of the class that creates the
* {@code TypeMismatch} to ensure that {@code a} and {@code b} are
* non-matching types.
*/
TypeMismatch(JSType a, JSType b) {
this.typeA = a;
this.typeB = b;
}
@Override public boolean equals(Object object) {
if (object instanceof TypeMismatch) {
TypeMismatch that = (TypeMismatch) object;
return (that.typeA.equals(this.typeA) && that.typeB
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.equals(this.typeB))
|| (that.typeB.equals(this.typeA) && that.typeA.equals(this.typeB));
}
return false;
}
@Override public int hashCode() {
return Objects.hashCode(typeA, typeB);
}
@Override public String toString() {
return "(" + typeA + ", " + typeB + ")";
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2009 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp.parsing;
import com.google.common.base.Preconditions;
import com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime;
/**
* This class implements the scanner for JsDoc strings.
*
* It is heavily based on Rhino's TokenStream.
*
*/
class JsDocTokenStream {
/*
* For chars - because we need something out-of-range
* to check. (And checking EOF by exception is annoying.)
* Note distinction from EOF token type!
*/
private final static int
EOF_CHAR = -1;
JsDocTokenStream(String sourceString) {
this(sourceString, 0);
}
JsDocTokenStream(String sourceString, int lineno) {
this(sourceString, lineno, 0);
}
JsDocTokenStream(String sourceString, int lineno, int initCharno) {
Preconditions.checkNotNull(sourceString);
this.lineno = lineno;
this.sourceString = sourceString;
this.sourceEnd = sourceString.length();
this.sourceCursor = this.cursor = 0;
this.initLineno = lineno;
this.initCharno = initCharno;
}
/**
* Tokenizes JSDoc comments.
*/
@SuppressWarnings("fallthrough")
final JsDocToken getJsDocToken() {
int c;
stringBufferTop = 0;
for (;;) {
// eat white spaces
for (;;) {
charno = -1;
c = getChar();
if (c == EOF_CHAR) {
return
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>c2)) {
ungetChar(c2);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
} else {
do {
c1 = c2;
c2 = getChar();
if (c1 == '.' && c2 == '<') {
ungetChar(c2);
ungetChar(c1);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
} else {
if (isJSDocString(c2)) {
addToString(c1);
} else {
ungetChar(c2);
addToString(c1);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return JsDocToken.STRING;
}
}
} while (true);
}
}
}
}
}
/**
* Gets the remaining JSDoc line without the {@link JsDocToken#EOL},
* {@link JsDocToken#EOF} or {@link JsDocToken#EOC}.
*/
@SuppressWarnings("fallthrough")
String getRemainingJSDocLine() {
int c;
for (;;) {
c = getChar();
switch (c) {
case '*':
if (peekChar() != '/') {
addToString(c);
break;
}
// fall through
case EOF_CHAR:
case '\n':
ungetChar(c);
this.string = getStringFromBuffer();
stringBufferTop = 0;
return this.string;
default:
addToString(c);
break;
}
}
}
final int getLineno() { return lineno; }
final int getCharno() {
return lineno == initLineno? initCharno + charno : charno;
}
final String getString() { return string; }
final boolean eof() { return hitEOF; }
private String getStringFromBuffer() {
tokenEnd = cursor;
return new String(stringBuffer, 0, stringBufferTop);
}
private void addToString(int c) {
int N = stringBufferTop;
if (N == stringBuffer.length) {
char[] tmp = new char[stringBuffer.length * 2];
System.arraycopy
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> == Character.FORMAT;
}
/**
* Allows the JSDocParser to update the character offset
* so that getCharno() returns a valid character position.
*/
void update() {
charno = getOffset();
}
private int peekChar() {
int c = getChar();
ungetChar(c);
return c;
}
protected int getChar() {
if (ungetCursor != 0) {
cursor++;
--ungetCursor;
if (charno == -1) {
charno = getOffset();
}
return ungetBuffer[ungetCursor];
}
for(;;) {
int c;
if (sourceCursor == sourceEnd) {
hitEOF = true;
if (charno == -1) {
charno = getOffset();
}
return EOF_CHAR;
}
cursor++;
c = sourceString.charAt(sourceCursor++);
if (lineEndChar >= 0) {
if (lineEndChar == '\r' && c == '\n') {
lineEndChar = '\n';
continue;
}
lineEndChar = -1;
lineStart = sourceCursor - 1;
lineno++;
}
if (c <= 127) {
if (c == '\n' || c == '\r') {
lineEndChar = c;
c = '\n';
}
} else {
if (isJSFormatChar(c)) {
continue;
}
if (ScriptRuntime.isJSLineTerminator(c)) {
lineEndChar = c;
c = '\n';
}
}
if (charno == -1) {
charno = getOffset();
}
return c;
}
}
private int getCharIgnoreLineEnd() {
if (ungetCursor != 0) {
cursor++;
--ungetCursor;
if (charno == -1) {
charno = getOffset();
}
return ungetBuffer[ungetCursor];
}
for(;;) {
int c;
if (sourceCursor == sourceEnd) {
hitEOF = true;
if (charno == -1) {
charno = getOffset();
}
return EOF_CHAR;
}
cursor++;
c = sourceString.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>charAt(sourceCursor++);
if (c <= 127) {
if (c == '\n' || c == '\r') {
lineEndChar = c;
c = '\n';
}
} else {
if (isJSFormatChar(c)) {
continue;
}
if (ScriptRuntime.isJSLineTerminator(c)) {
lineEndChar = c;
c = '\n';
}
}
if (charno == -1) {
charno = getOffset();
}
return c;
}
}
private void ungetCharIgnoreLineEnd(int c) {
ungetBuffer[ungetCursor++] = c;
cursor--;
}
/**
* Returns the offset into the current line.
*/
final int getOffset() {
return sourceCursor - lineStart - ungetCursor - 1;
}
// Set this to an initial non-null value so that the Parser has
// something to retrieve even if an error has occurred and no
// string is found. Fosters one class of error, but saves lots of
// code.
private String string = "";
private char[] stringBuffer = new char[128];
private int stringBufferTop;
// Room to backtrace from to < on failed match of the last - in <!--
private final int[] ungetBuffer = new int[3];
private int ungetCursor;
private boolean hitEOF = false;
private int lineStart = 0;
private int lineEndChar = -1;
int lineno;
private int charno = -1;
private int initCharno;
private int initLineno;
private String sourceString;
private int sourceEnd;
// sourceCursor is an index into a small buffer that keeps a
// sliding window of the source stream.
int sourceCursor;
// cursor is a monotonically increasing index into the original
// source stream, tracking exactly how far scanning has progressed.
// Its value is the index of the next character to be scanned.
int cursor;
// Record start and end positions of last scanned token.
int tokenBeg;
int tokenEnd;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
this.name = name;
}
@Override
public String getReferenceName() {
return name;
}
@Override
public String toString() {
return name;
}
@Override
public boolean isTemplateType() {
return true;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>_THIS = DiagnosticType.warning(
"JSC_USED_GLOBAL_THIS",
"dangerous use of the global 'this' object");
private final AbstractCompiler compiler;
/**
* If {@code assignLhsChild != null}, then the node being traversed is
* a descendant of the first child of an ASSIGN node. assignLhsChild's
* parent is this ASSIGN node.
*/
private Node assignLhsChild = null;
CheckGlobalThis(AbstractCompiler compiler) {
this.compiler = compiler;
}
/**
* Since this pass reports errors only when a global {@code this} keyword
* is encountered, there is no reason to traverse non global contexts.
*/
public boolean shouldTraverse(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.FUNCTION) {
// Don't traverse functions that are constructors or have the @this
// or @override annotation.
JSDocInfo jsDoc = getFunctionJsDocInfo(n);
if (jsDoc != null &&
(jsDoc.isConstructor() ||
jsDoc.isInterface() ||
jsDoc.hasThisType() ||
jsDoc.isOverride())) {
return false;
}
// Don't traverse functions unless they would normally
// be able to have a @this annotation associated with them. e.g.,
// var a = function() { }; // or
// function a() {} // or
// a.x = function() {}; // or
// var a = {x: function() {}};
int pType = parent.getType();
if (!(pType == Token.BLOCK ||
pType == Token.SCRIPT ||
pType == Token.NAME ||
pType == Token.ASSIGN ||
// object literal keys
pType == Token.STRING ||
pType == Token.NUMBER)) {
return false;
}
// Don't traverse functions that are getting lent to a prototype.
Node gramps = parent.getParent();
if (NodeUtil.isObjectLitKey(parent, gramps)) {
JSDocInfo maybeLends = gramps.getJSDocInfo();
if (maybeLends != null &&
maybeLends.getLendsName() != null &&
maybeLends.getLendsName().endsWith(".prototype"))
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
return false;
}
}
}
if (parent != null && parent.getType() == Token.ASSIGN) {
Node lhs = parent.getFirstChild();
Node rhs = lhs.getNext();
if (n == lhs) {
// Always traverse the left side of the assignment. To handle
// nested assignments properly (e.g., (a = this).property = c;),
// assignLhsChild should not be overridden.
if (assignLhsChild == null) {
assignLhsChild = lhs;
}
} else {
// Only traverse the right side if it's not an assignment to a prototype
// property or subproperty.
if (NodeUtil.isGet(lhs)) {
if (lhs.getType() == Token.GETPROP &&
lhs.getLastChild().getString().equals("prototype")) {
return false;
}
Node llhs = lhs.getFirstChild();
if (llhs.getType() == Token.GETPROP &&
llhs.getLastChild().getString().equals("prototype")) {
return false;
}
}
}
}
return true;
}
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.THIS && shouldReportThis(n, parent)) {
compiler.report(t.makeError(n, GLOBAL_THIS));
}
if (n == assignLhsChild) {
assignLhsChild = null;
}
}
private boolean shouldReportThis(Node n, Node parent) {
if (assignLhsChild != null) {
// Always report a THIS on the left side of an assign.
return true;
}
// Also report a THIS with a property access.
return parent != null && NodeUtil.isGet(parent);
}
/**
* Gets a function's JSDoc information, if it has any. Checks for a few
* patterns (ellipses show where JSDoc would be):
* <pre>
* ... function() {}
* ... x = function() {};
* var ... x = function() {};
* ... var x = function() {};
* </pre>
*/
private JSDocInfo getFunctionJsDocInfo(Node n) {
JSDocInfo jsDoc = n.getJSDocInfo();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ATE_PARAM", "Parse error. {0}");
static final DiagnosticType BAD_JSDOC_ANNOTATION =
DiagnosticType.warning("JSC_BAD_JSDOC_ANNOTATION", "Parse error. {0}");
// A map of Rhino messages to their DiagnosticType.
private final Map<Pattern, DiagnosticType> typeMap;
private final AbstractCompiler compiler;
/**
* For each message such as "Not a good use of {0}", replace the place
* holder {0} with a wild card that matches all possible strings.
* Also put the any non-place-holder in quotes for regex matching later.
*/
private Pattern replacePlaceHolders(String s) {
s = Pattern.quote(s);
return Pattern.compile(s.replaceAll("\\{\\d+\\}", "\\\\E.*\\\\Q"));
}
private RhinoErrorReporter(AbstractCompiler compiler) {
this.compiler = compiler;
typeMap = ImmutableMap.of(
// Extra @fileoverview
replacePlaceHolders(
ScriptRuntime.getMessage0("msg.jsdoc.fileoverview.extra")),
EXTRA_FILEOVERVIEW,
// Trailing comma
replacePlaceHolders(
com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime
.getMessage0("msg.extra.trailing.comma")),
TRAILING_COMMA,
// Duplicate parameter
replacePlaceHolders(
com.google.javascript.jscomp.mozilla.rhino.ScriptRuntime
.getMessage0("msg.dup.parms")),
DUPLICATE_PARAM,
// Unknown @annotations.
replacePlaceHolders(ScriptRuntime.getMessage0("msg.bad.jsdoc.tag")),
BAD_JSDOC_ANNOTATION,
// Type annotation errors.
Pattern.compile("^Bad type annotation.*"),
TYPE_PARSE_ERROR);
}
public static com.google.javascript.jscomp.mozilla.rhino.ErrorReporter
forNewRhino(AbstractCompiler compiler) {
return new NewRhinoErrorReporter(compiler);
}
public static ErrorReporter forOldRhino(AbstractCompiler compiler) {
return new OldRhinoErrorReporter(compiler);
}
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset) {
compiler.report(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Format);
}
/**
* Create a DiagnosticType at a given CheckLevel.
*
* @param name An identifier
* @param level Either CheckLevel.ERROR or CheckLevel.WARNING
* @param descriptionFormat A format string
* @return A new DiagnosticType
*/
public static DiagnosticType make(String name, CheckLevel level,
String descriptionFormat) {
return
new DiagnosticType(name, level, new MessageFormat(descriptionFormat));
}
/**
* Create a DiagnosticType. Private to force use of static factory methods.
*/
private DiagnosticType(String key, CheckLevel level, MessageFormat format) {
this.key = key;
this.defaultLevel = level;
this.format = format;
this.level = this.defaultLevel;
}
/**
* Create a description from the MessageFormat and the arguments.
* Used by unit tests.
*/
String format(Object ... arguments) {
return format.format(arguments);
}
@Override
public int compareTo(DiagnosticType diagnosticType) {
return key.compareTo(diagnosticType.key);
}
@Override
public String toString() {
return key + ": " + format.toPattern();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> public boolean isNullable() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.NUMBER_STRING_BOOLEAN)) ||
that.isObject()) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isBooleanValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.BOOLEAN_OBJECT_TYPE);
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public String getDisplayName() {
return "boolean";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseBooleanType();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.newArrayList();
for (Name name : namespace.getNameIndex().values()) {
if (name.docInfo != null && name.docInfo.isDefine()) {
// Process defines should not depend on check types being enabled,
// so we look for the JSDoc instead of the inferred type.
if (isValidDefineType(name.docInfo.getType())) {
allDefines.add(name);
} else {
JSError error = JSError.make(
name.declaration.sourceName,
name.declaration.node,
INVALID_DEFINE_TYPE_ERROR);
compiler.report(error);
}
} else if (name.refs != null) {
for (Ref ref : name.refs) {
Node n = ref.node;
Node parent = ref.node.getParent();
JSDocInfo info = n.getJSDocInfo();
if (info == null &&
parent.getType() == Token.VAR && parent.hasOneChild()) {
info = parent.getJSDocInfo();
}
if (info != null && info.isDefine()) {
allDefines.add(name);
break;
}
}
}
}
CollectDefines pass = new CollectDefines(compiler, allDefines);
NodeTraversal.traverse(compiler, root, pass);
return pass.getAllDefines();
}
/**
* Finds all assignments to @defines, and figures out the last value of
* the @define.
*/
private static final class CollectDefines implements Callback {
private final AbstractCompiler compiler;
private final Map<String, DefineInfo> assignableDefines;
private final Map<String, DefineInfo> allDefines;
private final Map<Node, RefInfo> allRefInfo;
// A hack that allows us to remove ASSIGN/VAR statements when
// we're currently visiting one of the children of the assign.
private Node lvalueToRemoveLater = null;
// A stack tied to the node traversal, to keep track of whether
// we're in a conditional block. If 1 is at the top, assignment to
// a define is allowed. Otherwise, it's not allowed.
private final Deque<Integer> assignAllowed;
CollectDefines(AbstractCompiler compiler, List<Name> listOfDefines) {
this.compiler = compiler;
this.allDefines = Maps.newHashMap
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> all the defines are at the top of the bundle.
for (DefineInfo info : assignableDefines.values()) {
setDefineInfoNotAssignable(info, t);
}
assignableDefines.clear();
}
}
updateAssignAllowedStack(n, false);
}
/**
* Determines whether assignment to a define should be allowed
* in the subtree of the given node, and if not, records that fact.
*
* @param n The node whose subtree we're about to enter or exit.
* @param entering True if we're entering the subtree, false otherwise.
*/
private void updateAssignAllowedStack(Node n, boolean entering) {
switch (n.getType()) {
case Token.CASE:
case Token.FOR:
case Token.FUNCTION:
case Token.HOOK:
case Token.IF:
case Token.SWITCH:
case Token.WHILE:
if (entering) {
assignAllowed.push(0);
} else {
assignAllowed.remove();
}
break;
}
}
/**
* Determines whether assignment to a define should be allowed
* at the current point of the traversal.
*/
private boolean isAssignAllowed() {
return assignAllowed.element() == 1;
}
/**
* Tracks the given define.
*
* @param t The current traversal, for context.
* @param name The full name for this define.
* @param value The value assigned to the define.
* @param valueParent The parent node of value.
* @return Whether we should remove this assignment from the parse tree.
*/
private boolean processDefineAssignment(NodeTraversal t,
String name, Node value, Node valueParent) {
if (value == null || !NodeUtil.isValidDefineValue(value,
allDefines.keySet())) {
compiler.report(
t.makeError(value, INVALID_DEFINE_INIT_ERROR, name));
} else if (!isAssignAllowed()) {
compiler.report(
t.makeError(valueParent, NON_GLOBAL_DEFINE_INIT_ERROR, name));
} else {
DefineInfo info = allDefines.get(name);
if (info == null) {
// First declaration of this define.
info = new DefineInfo(value, valueParent);
allDefines.put(name, info
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>);
assignableDefines.put(name, info);
} else if (info.recordAssignment(value)) {
// The define was already initialized, but this is a safe
// re-assignment.
return true;
} else {
// The define was already initialized, and this is an unsafe
// re-assignment.
compiler.report(
t.makeError(valueParent, DEFINE_NOT_ASSIGNABLE_ERROR,
name, info.getReasonWhyNotAssignable()));
}
}
return false;
}
/**
* Gets the parent node of the value for any assignment to a Name.
* For example, in the assignment
* {@code var x = 3;}
* the parent would be the NAME node.
*/
private static Node getValueParent(Ref ref) {
// there are two types of declarations: VARs and ASSIGNs
return ref.node.getParent() != null &&
ref.node.getParent().getType() == Token.VAR ?
ref.node : ref.node.getParent();
}
/**
* Records the fact that because of the current node in the node traversal,
* the define can't ever be assigned again.
*
* @param info Represents the define variable.
* @param t The current traversal.
*/
private void setDefineInfoNotAssignable(DefineInfo info, NodeTraversal t) {
info.setNotAssignable(format(REASON_DEFINE_NOT_ASSIGNABLE,
t.getLineNumber(), t.getSourceName()));
}
/**
* A simple data structure for associating a Ref with the name
* that it references.
*/
private static class RefInfo {
final Ref ref;
final Name name;
RefInfo(Ref ref, Name name) {
this.ref = ref;
this.name = name;
}
}
}
/**
* A simple class for storing information about a define.
* Gathers the initial value, the last assigned value, and whether
* the define can be safely assigned a new value.
*/
private static final class DefineInfo {
public final Node initialValueParent;
public final Node initialValue;
private Node lastValue;
private boolean isAssignable;
private String reasonNotAssignable;
/**
* Initializes a define.
*/
public DefineInfo(Node initialValue, Node initialValueParent) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
this.initialValueParent = initialValueParent;
this.initialValue = initialValue;
lastValue = initialValue;
isAssignable = true;
}
/**
* Records the fact that this define can't be assigned a value anymore.
*
* @param reason A message describing the reason why it can't be assigned.
*/
public void setNotAssignable(String reason) {
isAssignable = false;
reasonNotAssignable = reason;
}
/**
* Gets the reason why a define is not assignable.
*/
public String getReasonWhyNotAssignable() {
return reasonNotAssignable;
}
/**
* Records an assigned value.
*
* @return False if there was an error.
*/
public boolean recordAssignment(Node value) {
lastValue = value;
return isAssignable;
}
/**
* Gets the last assigned value.
*/
public Node getLastValue() {
return lastValue;
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Callback) {
this.scopeCallback = (ScopedCallback) cb;
}
this.compiler = compiler;
this.sourceName = "";
this.scopeCreator = scopeCreator;
}
private void throwUnexpectedException(Exception unexpectedException) {
// If there's an unexpected exception, try to get the
// line number of the code that caused it.
String message = unexpectedException.getMessage();
// TODO(user): It is possible to get more information if curNode or
// its parent is missing. We still have the scope stack in which it is still
// very useful to find out at least which function caused the exception.
if (!sourceName.isEmpty()) {
message =
unexpectedException.getMessage() + "\n" +
formatNodeContext("Node", curNode) +
(curNode == null ?
"" :
formatNodeContext("Parent", curNode.getParent()));
}
compiler.throwInternalError(message, unexpectedException);
}
private String formatNodeContext(String label, Node n) {
if (n == null) {
return " " + label + ": NULL";
}
return " " + label + "(" + n.toString(false, false, false) + "): "
+ formatNodePosition(n);
}
/**
* Traverses a parse tree recursively.
*/
public void traverse(Node root) {
try {
sourceName = "";
curNode = root;
pushScope(root);
traverseBranch(root, null);
popScope();
} catch (Exception unexpectedException) {
throwUnexpectedException(unexpectedException);
}
}
public void traverseRoots(Node ... roots) {
traverseRoots(Lists.newArrayList(roots));
}
public void traverseRoots(List<Node> roots) {
if (roots.isEmpty()) {
return;
}
try {
Node scopeRoot = roots.get(0).getParent();
Preconditions.checkState(scopeRoot != null);
sourceName = "";
curNode = scopeRoot;
pushScope(scopeRoot);
for (Node root : roots) {
Preconditions.checkState(root.getParent() == scopeRoot);
traverseBranch(root, scopeRoot);
}
popScope();
} catch (Exception unexpectedException) {
throwUnexpectedException(unexpectedException);
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> private static final String MISSING_SOURCE = "[source unknown]";
private String formatNodePosition(Node n) {
if (n == null) {
return MISSING_SOURCE + "\n";
}
int lineNumber = n.getLineno();
int columnNumber = n.getCharno();
String src = compiler.getSourceLine(sourceName, lineNumber);
if (src == null) {
src = MISSING_SOURCE;
}
return sourceName + ":" + lineNumber + ":" + columnNumber + "\n"
+ src + "\n";
}
/**
* Traverses a parse tree recursively with a scope, starting with the given
* root. This should only be used in the global scope. Otherwise, use
* {@link #traverseAtScope}.
*/
void traverseWithScope(Node root, Scope s) {
Preconditions.checkState(s.isGlobal());
sourceName = "";
curNode = root;
pushScope(s);
traverseBranch(root, null);
popScope();
}
/**
* Traverses a parse tree recursively with a scope, starting at that scope's
* root.
*/
void traverseAtScope(Scope s) {
Node n = s.getRootNode();
if (n.getType() == Token.FUNCTION) {
// We need to do some extra magic to make sure that the scope doesn't
// get re-created when we dive into the function.
sourceName = getSourceName(n);
curNode = n;
pushScope(s);
Node args = n.getFirstChild().getNext();
Node body = args.getNext();
traverseBranch(args, n);
traverseBranch(body, n);
popScope();
} else {
traverseWithScope(n, s);
}
}
/**
* Traverses an inner node recursively with a refined scope. An inner node may
* be any node with a non {@code null} parent (i.e. all nodes except the
* root).
*
* @param node the node to traverse
* @param parent the node's parent, it may be not be {@code null}
* @param refinedScope the refined scope of the scope currently at the top of
* the scope stack or in trivial cases that very scope or {@code null}
*/
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.g. when entering a function). */
private void pushScope(Node node) {
Preconditions.checkState(curNode != null);
scopeRoots.push(node);
cfgs.push(null);
if (scopeCallback != null) {
scopeCallback.enterScope(this);
}
}
/** Creates a new scope (e.g. when entering a function). */
private void pushScope(Scope s) {
Preconditions.checkState(curNode != null);
scopes.push(s);
cfgs.push(null);
if (scopeCallback != null) {
scopeCallback.enterScope(this);
}
}
/** Pops back to the previous scope (e.g. when leaving a function). */
private void popScope() {
if (scopeCallback != null) {
scopeCallback.exitScope(this);
}
if (scopeRoots.isEmpty()) {
scopes.pop();
} else {
scopeRoots.pop();
}
cfgs.pop();
}
/** Gets the current scope. */
public Scope getScope() {
Scope scope = scopes.isEmpty() ? null : scopes.peek();
if (scopeRoots.isEmpty()) {
return scope;
}
Iterator<Node> it = scopeRoots.descendingIterator();
while (it.hasNext()) {
scope = scopeCreator.createScope(it.next(), scope);
scopes.push(scope);
}
scopeRoots.clear();
return scope;
}
/** Gets the control flow graph for the current JS scope. */
public ControlFlowGraph<Node> getControlFlowGraph() {
if (cfgs.peek() == null) {
ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, true);
cfa.process(null, getScopeRoot());
cfgs.pop();
cfgs.push(cfa.getCfg());
}
return cfgs.peek();
}
/** Returns the current scope's root. */
public Node getScopeRoot() {
if (scopeRoots.isEmpty()) {
return scopes.peek().getRootNode();
} else {
return scopeRoots.peek();
}
}
/**
* Determines whether the traversal is currently in the global scope.
*/
boolean inGlobalScope() {
return getScopeDepth() <= 1
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> false;
idGenerators = Collections.emptySet();
replaceStringsFunctionDescriptions = Collections.emptyList();
replaceStringsPlaceholderToken = "";
replaceStringsReservedStrings = Collections.emptySet();
// Output
printInputDelimiter = false;
prettyPrint = false;
lineBreak = false;
reportPath = null;
tracer = TracerMode.OFF;
colorizeErrorOutput = false;
errorFormat = ErrorFormat.SINGLELINE;
warningsGuard = null;
debugFunctionSideEffectsPath = null;
jsOutputFile = "";
externExports = false;
nameReferenceReportPath = null;
nameReferenceGraphPath = null;
// Debugging
aliasHandler = NULL_ALIAS_TRANSFORMATION_HANDLER;
operaCompoundAssignFix = true;
}
/**
* Returns the map of define replacements.
*/
public Map<String, Node> getDefineReplacements() {
return getReplacementsHelper(defineReplacements);
}
/**
* Returns the map of tweak replacements.
*/
public Map<String, Node> getTweakReplacements() {
return getReplacementsHelper(tweakReplacements);
}
/**
* Creates a map of String->Node from a map of String->Number/String/Boolean.
*/
private static Map<String, Node> getReplacementsHelper(
Map<String, Object> source) {
Map<String, Node> map = Maps.newHashMap();
for (Map.Entry<String, Object> entry : source.entrySet()) {
String name = entry.getKey();
Object value = entry.getValue();
if (value instanceof Boolean) {
map.put(name, ((Boolean) value).booleanValue() ?
new Node(Token.TRUE) : new Node(Token.FALSE));
} else if (value instanceof Integer) {
map.put(name, Node.newNumber(((Integer) value).intValue()));
} else if (value instanceof Double) {
map.put(name, Node.newNumber(((Double) value).doubleValue()));
} else {
Preconditions.checkState(value instanceof String);
map.put(name, Node.newString((String) value));
}
}
return map;
}
/**
* Sets the value of the {@code @define} variable in JS
* to a boolean literal.
*/
public void
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> setDefineToBooleanLiteral(String defineName, boolean value) {
defineReplacements.put(defineName, new Boolean(value));
}
/**
* Sets the value of the {@code @define} variable in JS to a
* String literal.
*/
public void setDefineToStringLiteral(String defineName, String value) {
defineReplacements.put(defineName, value);
}
/**
* Sets the value of the {@code @define} variable in JS to a
* number literal.
*/
public void setDefineToNumberLiteral(String defineName, int value) {
defineReplacements.put(defineName, new Integer(value));
}
/**
* Sets the value of the {@code @define} variable in JS to a
* number literal.
*/
public void setDefineToDoubleLiteral(String defineName, double value) {
defineReplacements.put(defineName, new Double(value));
}
/**
* Sets the value of the tweak in JS
* to a boolean literal.
*/
public void setTweakToBooleanLiteral(String tweakId, boolean value) {
tweakReplacements.put(tweakId, new Boolean(value));
}
/**
* Sets the value of the tweak in JS to a
* String literal.
*/
public void setTweakToStringLiteral(String tweakId, String value) {
tweakReplacements.put(tweakId, value);
}
/**
* Sets the value of the tweak in JS to a
* number literal.
*/
public void setTweakToNumberLiteral(String tweakId, int value) {
tweakReplacements.put(tweakId, new Integer(value));
}
/**
* Sets the value of the tweak in JS to a
* number literal.
*/
public void setTweakToDoubleLiteral(String tweakId, double value) {
tweakReplacements.put(tweakId, new Double(value));
}
/**
* Skip all possible passes, to make the compiler as fast as possible.
*/
public void skipAllCompilerPasses() {
skipAllPasses = true;
}
/**
* Whether the warnings guard in this Options object enables the given
* group of warnings.
*/
boolean enables(DiagnosticGroup type) {
return warningsGuard != null && warningsGuard.enables
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Configuration(
String placeholderToken, List<String> functionDescriptors) {
this.replaceStringsPlaceholderToken = placeholderToken;
this.replaceStringsFunctionDescriptions =
Lists.newArrayList(functionDescriptors);
}
public void setRewriteNewDateGoogNow(boolean rewrite) {
this.rewriteNewDateGoogNow = rewrite;
}
public void setRemoveAbstractMethods(boolean remove) {
this.removeAbstractMethods = remove;
}
public void setRemoveClosureAsserts(boolean remove) {
this.removeClosureAsserts = remove;
}
/**
* If true, name anonymous functions only. All other passes will be skipped.
*/
public void setNameAnonymousFunctionsOnly(boolean value) {
this.nameAnonymousFunctionsOnly = value;
}
public void lineLengthThreshold(int value) {
this.lineLengthThreshold = value;
}
public void setColorizeErrorOutput(boolean colorizeErrorOutput) {
this.colorizeErrorOutput = colorizeErrorOutput;
}
public boolean shouldColorizeErrorOutput() {
return colorizeErrorOutput;
}
/**
* If true, chain calls to functions that return this.
*/
public void setChainCalls(boolean value) {
this.chainCalls = value;
}
/**
* If true, accept `const' keyword.
*/
public void setAcceptConstKeyword(boolean value) {
this.acceptConstKeyword = value;
}
/**
* Enable runtime type checking, which adds JS type assertions for debugging.
*
* @param logFunction A JS function to be used for logging runtime type
* assertion failures.
*/
public void enableRuntimeTypeCheck(String logFunction) {
this.runtimeTypeCheck = true;
this.runtimeTypeCheckLogFunction = logFunction;
}
public void disableRuntimeTypeCheck() {
this.runtimeTypeCheck = false;
}
public void setGenerateExports(boolean generateExports) {
this.generateExports = generateExports;
}
public void setCodingConvention(CodingConvention codingConvention) {
this.codingConvention = codingConvention;
}
public CodingConvention getCodingConvention() {
return codingConvention;
}
/**
* Sort inputs by their goog.provide/goog.require calls, and prune inputs
* whose symbols are not required.
*/
public void
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
// Note: Constant properties annotations are not propagated.
if (n.getType() == Token.NAME) {
if (n.getString().isEmpty()) {
return;
}
JSDocInfo info = null;
// Find the JSDocInfo for a top level variable.
Var var = t.getScope().getVar(n.getString());
if (var != null) {
info = var.getJSDocInfo();
}
boolean shouldBeConstant =
(info != null && info.isConstant()) ||
NodeUtil.isConstantByConvention(
compiler.getCodingConvention(), n, parent);
boolean isMarkedConstant = n.getBooleanProp(Node.IS_CONSTANT_NAME);
if (shouldBeConstant && !isMarkedConstant) {
if (assertOnChange) {
String name = n.getString();
throw new IllegalStateException(
"Unexpected const change.\n" +
" name: "+ name + "\n" +
" parent:" + n.getParent().toStringTree());
}
n.putBooleanProp(Node.IS_CONSTANT_NAME, true);
}
}
}
}
/**
* Walk the AST tree and verify that constant names are used consistently.
*/
static class VerifyConstants extends AbstractPostOrderCallback
implements CompilerPass {
final private AbstractCompiler compiler;
final private boolean checkUserDeclarations;
VerifyConstants(AbstractCompiler compiler, boolean checkUserDeclarations) {
this.compiler = compiler;
this.checkUserDeclarations = checkUserDeclarations;
}
@Override
public void process(Node externs, Node root) {
Node externsAndJs = root.getParent();
Preconditions.checkState(externsAndJs != null);
Preconditions.checkState(externsAndJs.hasChild(externs));
NodeTraversal.traverseRoots(
compiler, Lists.newArrayList(externs, root), this);
}
private Map<String, Boolean> constantMap = Maps.newHashMap();
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.NAME) {
String name = n.getString();
if (n.getString().isEmpty()) {
return;
}
boolean isConst = n
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.getBooleanProp(Node.IS_CONSTANT_NAME);
if (checkUserDeclarations) {
boolean expectedConst = false;
CodingConvention convention = compiler.getCodingConvention();
if (NodeUtil.isConstantName(n)
|| NodeUtil.isConstantByConvention(convention, n, parent)) {
expectedConst = true;
} else {
expectedConst = false;
JSDocInfo info = null;
Var var = t.getScope().getVar(n.getString());
if (var != null) {
info = var.getJSDocInfo();
}
if (info != null && info.isConstant()) {
expectedConst = true;
} else {
expectedConst = false;
}
}
if (expectedConst) {
Preconditions.checkState(expectedConst == isConst,
"The name " + name + " is not annotated as constant.");
} else {
Preconditions.checkState(expectedConst == isConst,
"The name " + name + " should not be annotated as constant.");
}
}
Boolean value = constantMap.get(name);
if (value == null) {
constantMap.put(name, isConst);
} else {
Preconditions.checkState(value.booleanValue() == isConst,
"The name " + name + " is not consistently annotated as " +
"constant.");
}
}
}
}
/**
* Simplify the AST:
* - VAR declarations split, so they represent exactly one child
* declaration.
* - WHILEs are converted to FORs
* - FOR loop are initializers are moved out of the FOR structure
* - LABEL node of children other than LABEL, BLOCK, WHILE, FOR, or DO are
* moved into a block.
* - Add constant annotations based on coding convention.
*/
static class NormalizeStatements implements Callback {
private final AbstractCompiler compiler;
private final boolean assertOnChange;
NormalizeStatements(AbstractCompiler compiler, boolean assertOnChange) {
this.compiler = compiler;
this.assertOnChange = assertOnChange;
}
private void reportCodeChange(String changeDescription) {
if (assertOnChange) {
throw new IllegalStateException(
"Normalize constraints violated:\n" + changeDescription);
}
compiler.reportCodeChange();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>HashSet();
/**
* Remove duplicate VAR declarations encountered discovered during
* scope creation.
*/
@Override
public void onRedeclaration(
Scope s, String name, Node n, CompilerInput input) {
Preconditions.checkState(n.getType() == Token.NAME);
Node parent = n.getParent();
Var v = s.getVar(name);
if (v != null && s.isGlobal()) {
// We allow variables to be duplicate declared if one
// declaration appears in source and the other in externs.
// This deals with issues where a browser built-in is declared
// in one browser but not in another.
if (v.isExtern() && !input.isExtern()) {
if (hasOkDuplicateDeclaration.add(v)) {
return;
}
}
}
// If name is "arguments", Var maybe null.
if (v != null && v.getParentNode().getType() == Token.CATCH) {
// Redeclaration of a catch expression variable is hard to model
// without support for "with" expressions.
// The EcmaScript spec (section 12.14), declares that a catch
// "catch (e) {}" is handled like "with ({'e': e}) {}" so that
// "var e" would refer to the scope variable, but any following
// reference would still refer to "e" of the catch expression.
// Until we have support for this disallow it.
// Currently the Scope object adds the catch expression to the
// function scope, which is technically not true but a good
// approximation for most uses.
// TODO(johnlenz): Consider improving how scope handles catch
// expression.
// Use the name of the var before it was made unique.
name = MakeDeclaredNamesUnique.ContextualRenameInverter.getOrginalName(
name);
compiler.report(
JSError.make(
input.getName(), n,
CATCH_BLOCK_VAR_ERROR, name));
} else if (v != null && parent.getType() == Token.FUNCTION) {
if (v.getParentNode().getType() == Token.VAR) {
s.undeclare(v);
s.declare(name, n, n.getJSType(), v.input);
replaceVarWithAssignment(v.getName
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Node(), v.getParentNode(),
v.getParentNode().getParent());
}
} else if (parent.getType() == Token.VAR) {
Preconditions.checkState(parent.hasOneChild());
replaceVarWithAssignment(n, parent, parent.getParent());
}
}
/**
* Remove the parent VAR. There are three cases that need to be handled:
* 1) "var a = b;" which is replaced with "a = b"
* 2) "label:var a;" which is replaced with "label:;". Ideally, the
* label itself would be removed but that is not possible in the
* context in which "onRedeclaration" is called.
* 3) "for (var a in b) ..." which is replaced with "for (a in b)..."
* Cases we don't need to handle are VARs with multiple children,
* which have already been split into separate declarations, so there
* is no need to handle that here, and "for (var a;;);", which has
* been moved out of the loop.
* The result of this is that in each case the parent node is replaced
* which is generally dangerous in a traversal but is fine here with
* the scope creator, as the next node of interest is the parent's
* next sibling.
*/
private void replaceVarWithAssignment(Node n, Node parent, Node gramps) {
if (n.hasChildren()) {
// The * is being initialize, preserve the new value.
parent.removeChild(n);
// Convert "var name = value" to "name = value"
Node value = n.getFirstChild();
n.removeChild(value);
Node replacement = new Node(Token.ASSIGN, n, value);
replacement.copyInformationFrom(parent);
gramps.replaceChild(parent, NodeUtil.newExpr(replacement));
} else {
// It is an empty reference remove it.
if (NodeUtil.isStatementBlock(gramps)) {
gramps.removeChild(parent);
} else if (gramps.getType() == Token.FOR) {
// This is the "for (var a in b)..." case. We don't need to worry
// about initializers in "for
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
public TernaryValue testForEquality(JSType that) {
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isStringValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public String getDisplayName() {
return "string";
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.STRING_OBJECT_TYPE);
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseStringType();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> reservedNames;
this.prefix = prefix;
// build the character arrays to use
this.firstChars = reserveCharacters(FIRST_CHAR, reservedCharacters);
this.nonFirstChars = reserveCharacters(NONFIRST_CHAR, reservedCharacters);
checkPrefix(prefix);
}
/**
* Provides the array of available characters based on the specified arrays.
* @param chars The list of characters that are legal
* @param reservedCharacters The characters that should not be used
* @return An array of characters to use. Will return the chars array if
* reservedCharacters is null or empty, otherwise creates a new array.
*/
static char[] reserveCharacters(char[] chars, char[] reservedCharacters) {
if (reservedCharacters == null || reservedCharacters.length == 0) {
return chars;
}
Set<Character> charSet = Sets.newLinkedHashSet(Chars.asList(chars));
for (char reservedCharacter : reservedCharacters) {
charSet.remove(reservedCharacter);
}
return Chars.toArray(charSet);
}
/** Validates a name prefix. */
private void checkPrefix(String prefix) {
if (prefix.length() > 0) {
// Make sure that prefix starts with a legal character.
if (!contains(firstChars, prefix.charAt(0))) {
throw new IllegalArgumentException("prefix must start with one of: " +
Arrays.toString(firstChars));
}
for (int pos = 1; pos < prefix.length(); ++pos) {
if (!contains(nonFirstChars, prefix.charAt(pos))) {
throw new IllegalArgumentException("prefix has invalid characters, " +
"must be one of: " +
Arrays.toString(nonFirstChars));
}
}
}
}
private boolean contains(char[] arr, char c) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == c) {
return true;
}
}
return false;
}
/**
* Generates the next short name.
*/
String generateNextName() {
while (true) {
String name = prefix;
int i = nameCount;
if (name.isEmpty()) {
int pos = i % firstChars.length;
name += firstChars[pos];
i /=
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> firstChars.length;
}
while (i > 0) {
i--;
int pos = i % nonFirstChars.length;
name += nonFirstChars[pos];
i /= nonFirstChars.length;
}
nameCount++;
// Make sure it's not a JS keyword or reserved name.
if (TokenStream.isKeyword(name) || reservedNames.contains(name)) {
continue;
}
return name;
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> *
* @param js Inputs
* @param expected Expected JS output
*/
public void test(String[] js, String[] expected) {
test(js, expected, null);
}
/**
* Verifies that the compiler pass's JS output matches the expected output,
* or that an expected error is encountered.
*
* @param js Inputs
* @param expected Expected JS output
* @param error Expected error, or null if no error is expected
*/
public void test(String[] js, String[] expected, DiagnosticType error) {
test(js, expected, error, null);
}
/**
* Verifies that the compiler pass's JS output matches the expected output
* and (optionally) that an expected warning is issued. Or, if an error is
* expected, this method just verifies that the error is encountered.
*
* @param js Inputs
* @param expected Expected JS output
* @param error Expected error, or null if no error is expected
* @param warning Expected warning, or null if no warning is expected
*/
public void test(String[] js, String[] expected, DiagnosticType error,
DiagnosticType warning) {
test(js, expected, error, warning, null);
}
/**
* Verifies that the compiler pass's JS output matches the expected output
* and (optionally) that an expected warning is issued. Or, if an error is
* expected, this method just verifies that the error is encountered.
*
* @param js Inputs
* @param expected Expected JS output
* @param error Expected error, or null if no error is expected
* @param warning Expected warning, or null if no warning is expected
* @param description The description of the expected warning,
* or null if no warning is expected or if the warning's description
* should not be examined
*/
public void test(String[] js, String[] expected, DiagnosticType error,
DiagnosticType warning, String description) {
Compiler compiler = createCompiler();
lastCompiler = compiler;
JSSourceFile[] inputs = new JSSourceFile[js.length];
for (int i = 0; i < js.length; i++) {
inputs[i] = JSSourceFile.fromCode("input" + i, js[i]);
}
compiler.init(extern
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ourceFile[]{
JSSourceFile.fromCode("externs", externs)
};
test(externsInputs, js, js, null, warning, description);
}
/**
* Verifies that the compiler pass's JS output is the same as its input.
*
* @param js Inputs and outputs
*/
public void testSame(String[] js) {
test(js, js);
}
/**
* Verifies that the compiler pass's JS output is the same as its input,
* and emits the given error.
*
* @param js Inputs and outputs
* @param error Expected error, or null if no error is expected
*/
public void testSame(String[] js, DiagnosticType error) {
test(js, js, error);
}
/**
* Verifies that the compiler pass's JS output is the same as its input,
* and emits the given error and warning.
*
* @param js Inputs and outputs
* @param error Expected error, or null if no error is expected
* @param warning Expected warning, or null if no warning is expected
*/
public void testSame(
String[] js, DiagnosticType error, DiagnosticType warning) {
test(js, js, error, warning);
}
/**
* Verifies that the compiler pass's JS output is the same as the input.
*
* @param modules Module inputs
*/
public void testSame(JSModule[] modules) {
testSame(modules, null);
}
/**
* Verifies that the compiler pass's JS output is the same as the input.
*
* @param modules Module inputs
* @param warning A warning, or null for no expected warning.
*/
public void testSame(JSModule[] modules, DiagnosticType warning) {
try {
String[] expected = new String[modules.length];
for (int i = 0; i < modules.length; i++) {
expected[i] = "";
for (CompilerInput input : modules[i].getInputs()) {
expected[i] += input.getSourceFile().getCode();
}
}
test(modules, expected, null, warning);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Verifies that the compiler pass's JS output matches the expected output
* and (
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> processing",
recentChange.hasCodeChanged());
for (int i = 0; i < numRepetitions; ++i) {
if (compiler.getErrorCount() == 0) {
errorManagers[i] = new BlackHoleErrorManager(compiler);
// Only run the type checking pass once, if asked.
// Running it twice can cause unpredictable behavior because duplicate
// objects for the same type are created, and the type system
// uses reference equality to compare many types.
if (typeCheckEnabled && i == 0) {
TypeCheck check = createTypeCheck(compiler, typeCheckLevel);
check.processForTesting(externsRoot, mainRoot);
}
// Only run the normalize pass once, if asked.
if (normalizeEnabled && i == 0) {
normalizeActualCode(compiler, externsRoot, mainRoot);
}
if (markNoSideEffects && i == 0) {
MarkNoSideEffectCalls mark = new MarkNoSideEffectCalls(compiler);
mark.process(externsRoot, mainRoot);
}
recentChange.reset();
getProcessor(compiler).process(externsRoot, mainRoot);
if (checkLineNumbers) {
(new LineNumberCheck(compiler)).process(externsRoot, mainRoot);
}
hasCodeChanged = hasCodeChanged || recentChange.hasCodeChanged();
aggregateWarningCount += errorManagers[i].getWarningCount();
aggregateWarnings.addAll(Lists.newArrayList(compiler.getWarnings()));
if (normalizeEnabled) {
boolean verifyDeclaredConstants = true;
new Normalize.VerifyConstants(compiler, verifyDeclaredConstants)
.process(externsRoot, mainRoot);
}
}
}
if (error == null) {
assertEquals(
"Unexpected error(s): " + Joiner.on("\n").join(compiler.getErrors()),
0, compiler.getErrorCount());
// Verify the symbol table.
ErrorManager symbolTableErrorManager =
new BlackHoleErrorManager(compiler);
Node expectedRoot = parseExpectedJs(expected);
expectedRoot.detachFromParent();
JSError[] stErrors = symbolTableErrorManager.getErrors();
if (expectedSymbolTableError != null) {
assertEquals("There should be one error.", 1, stErrors.length);
assertEquals(expectedSymbolTable
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Error, stErrors[0].getType());
} else {
assertEquals("Unexpected symbol table error(s): " +
Joiner.on("\n").join(stErrors),
0, stErrors.length);
}
if (warning == null) {
assertEquals(
"Unexpected warning(s): " + Joiner.on("\n").join(aggregateWarnings),
0, aggregateWarningCount);
} else {
assertEquals("There should be one warning, repeated " + numRepetitions +
" time(s).", numRepetitions, aggregateWarningCount);
for (int i = 0; i < numRepetitions; ++i) {
JSError[] warnings = errorManagers[i].getWarnings();
JSError actual = warnings[0];
assertEquals(warning, actual.getType());
// Make sure that source information is always provided.
if (!allowSourcelessWarnings) {
assertTrue("Missing source file name in warning",
actual.sourceName != null && !actual.sourceName.isEmpty());
assertTrue("Missing line number in warning",
-1 != actual.lineNumber);
assertTrue("Missing char number in warning",
-1 != actual.getCharno());
}
if (description != null) {
assertEquals(description, actual.description);
}
}
}
if (normalizeEnabled) {
normalizeActualCode(compiler, externsRootClone, mainRootClone);
}
boolean codeChange = !mainRootClone.isEquivalentTo(mainRoot);
boolean externsChange = !externsRootClone.isEquivalentTo(externsRoot);
// Generally, externs should not be change by the compiler passes.
if (externsChange && !allowExternsChanges) {
String explanation = externsRootClone.checkTreeEquals(externsRoot);
fail("Unexpected changes to externs" +
"\nExpected: " + compiler.toSource(externsRootClone) +
"\nResult: " + compiler.toSource(externsRoot) +
"\n" + explanation);
}
if (!codeChange && !externsChange) {
assertFalse(
"compiler.reportCodeChange() was called " +
"even though nothing changed",
hasCodeChanged);
} else {
assertTrue("compiler.reportCodeChange() should have been called",
hasCodeChanged
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Error : compiler.getWarnings()) {
warnings += actualError.description + "\n";
}
assertEquals("There should be one warning. " + warnings,
1, compiler.getWarningCount());
assertEquals(warnings, warning, compiler.getWarnings()[0].getType());
}
}
}
private void normalizeActualCode(
Compiler compiler, Node externsRoot, Node mainRoot) {
Normalize normalize = new Normalize(compiler, false);
normalize.process(externsRoot, mainRoot);
}
/**
* Parses expected js inputs and returns the root of the parse tree.
*/
protected Node parseExpectedJs(String[] expected) {
Compiler compiler = createCompiler();
JSSourceFile[] inputs = new JSSourceFile[expected.length];
for (int i = 0; i < expected.length; i++) {
inputs[i] = JSSourceFile.fromCode("expected" + i, expected[i]);
}
compiler.init(externsInputs, inputs, getOptions());
Node root = compiler.parseInputs();
assertTrue("Unexpected parse error(s): " +
Joiner.on("\n").join(compiler.getErrors()), root != null);
Node externsRoot = root.getFirstChild();
Node mainRoot = externsRoot.getNext();
// Only run the normalize pass, if asked.
if (normalizeEnabled && normalizeExpected && !compiler.hasErrors()) {
Normalize normalize = new Normalize(compiler, false);
normalize.process(externsRoot, mainRoot);
}
return mainRoot;
}
protected Node parseExpectedJs(String expected) {
return parseExpectedJs(new String[] {expected});
}
/**
* Generates a list of modules from a list of inputs, such that each module
* depends on the module before it.
*/
static JSModule[] createModuleChain(String... inputs) {
JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[i - 1]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs, such that each module
* depends on the first module.
*/
static JSModule[] createModuleStar(String... inputs) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[0]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs, such that modules
* form a bush formation. In a bush formation, module 2 depends
* on module 1, and all other modules depend on module 2.
*/
static JSModule[] createModuleBush(String ... inputs) {
Preconditions.checkState(inputs.length > 2);
JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[i == 1 ? 0 : 1]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs, such that modules
* form a tree formation. In a tree formation, module N depends on
* module `floor(N/2)`, So the modules form a balanced binary tree.
*/
static JSModule[] createModuleTree(String ... inputs) {
JSModule[] modules = createModules(inputs);
for (int i = 1; i < modules.length; i++) {
modules[i].addDependency(modules[(i - 1) / 2]);
}
return modules;
}
/**
* Generates a list of modules from a list of inputs. Does not generate any
* dependencies between the modules.
*/
static JSModule[] createModules(String... inputs) {
JSModule[] modules = new JSModule[inputs.length];
for (int i = 0; i < inputs.length; i++) {
JSModule module = modules[i] = new JSModule("m" + i);
module.add(JSSourceFile.fromCode("i" + i, inputs[i]));
}
return modules;
}
private static class BlackHoleErrorManager extends BasicErrorManager {
private BlackHoleErrorManager(Compiler compiler) {
compiler.setErrorManager(this);
}
@Override
public void println(CheckLevel level, JSError error) {}
@Override
public void printSummary() {}
}
Compiler createCompiler() {
Compiler compiler
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>+=1");
testParseError("(x||y)+=1", INVALID_ASSIGNMENT_TARGET);
testParseError("(x?y:z)+=1", INVALID_ASSIGNMENT_TARGET);
testParseError("f()+=1", INVALID_ASSIGNMENT_TARGET);
testParseError("f()++", INVALID_INCREMENT_TARGET);
testParseError("f()--", INVALID_DECREMENT_TARGET);
testParseError("++f()", INVALID_INCREMENT_TARGET);
testParseError("--f()", INVALID_DECREMENT_TARGET);
}
private void testNoParseError(String string) {
testParseError(string, (String)null);
}
private void testParseError(String string, String error) {
testParseError(string, error == null ? null : new String[] { error });
}
private void testParseError(String string, String[] errors) {
Node root = newParse(string, new TestErrorReporter(errors, null));
assertTrue("unexpected warnings reported",
errorReporter.hasEncounteredAllWarnings());
assertTrue("expected error were not reported",
errorReporter.hasEncounteredAllErrors());
}
private void assertMarkerPosition(Node n, int lineno, int charno) {
int count = 0;
for (JSDocInfo.Marker marker : n.getJSDocInfo().getMarkers()) {
assertEquals(lineno, marker.annotation.getStartLine());
assertEquals(charno, marker.annotation.getPositionOnStartLine());
count++;
}
assertEquals(1, count);
}
private void assertNodePosition(int lineno, int charno, Node n) {
assertEquals("Line number", lineno, n.getLineno());
assertEquals("Column position", charno, n.getCharno());
}
private void testNewParser(String code, String expected) {
String actual = newParse(code).toStringTree();
assertEquals(expected, actual);
}
private void parse(String string) {
String compare = newParse(string).checkTreeEquals(oldParse(string));
assertTrue(compare, compare == null);
}
private Node newParse(String string) {
return newParse(string, new TestErrorReporter(null, null));
}
private Node newParse(String string, TestErrorReporter errorReporter) {
CompilerEnvirons environment = new CompilerEnvirons();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> the explanation of checked unknown types in JSTypeNative.
private final boolean isChecked;
UnknownType(JSTypeRegistry registry, boolean isChecked) {
super(registry);
this.isChecked = isChecked;
}
@Override
public boolean isUnknownType() {
return true;
}
@Override
public boolean isCheckedUnknownType() {
return isChecked;
}
@Override
public boolean canAssignTo(JSType that) {
return true;
}
@Override
public boolean canBeCalled() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseUnknownType();
}
@Override
public String toString() {
return getReferenceName();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns, Node propertyNode) {
// nothing to define
return true;
}
@Override
public ObjectType getImplicitPrototype() {
return null;
}
@Override
public int getPropertiesCount() {
return Integer.MAX_VALUE;
}
@Override
void collectPropertyNames(Set<String> props) {
}
@Override
public JSType getPropertyType(String propertyName) {
return this;
}
@Override
public boolean hasProperty(String propertyName) {
return true;
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public String getReferenceName() {
return isChecked ? "??" : "?";
}
@Override
public String getDisplayName() {
return "Unknown";
}
@Override
public boolean hasDisplayName() {
return true;
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return false;
}
@Override
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> private static final long serialVersionUID = 1L;
VoidType(JSTypeRegistry registry) {
super(registry);
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
if (UNKNOWN.equals(super.testForEquality(that))) {
return UNKNOWN;
}
if (that.isSubtype(this) ||
that.isSubtype(getNativeType(JSTypeNative.NULL_TYPE))) {
return TRUE;
}
return FALSE;
}
@Override
public boolean matchesNumberContext() {
return false;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean isVoidType() {
return true;
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public String getDisplayName() {
return "undefined";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseVoidType();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>primarily for debugging). */
@Override
public String toString() {
return name;
}
/**
* Removes any references to nodes of the AST. This method is needed to
* allow the ASTs to be garbage collected if the modules are kept around.
*/
public void clearAsts() {
for (CompilerInput input : inputs) {
input.clearAst();
}
}
/**
* Puts the JS files into a topologically sorted order by their dependencies.
*/
public void sortInputsByDeps(Compiler compiler) {
// Set the compiler, so that we can parse requires/provides and report
// errors properly.
for (CompilerInput input : inputs) {
input.setCompiler(compiler);
}
// Sort the JSModule in this order.
try {
List<CompilerInput> sortedList =
(new SortedDependencies<CompilerInput>(
Collections.<CompilerInput>unmodifiableList(inputs)))
.getSortedList();
inputs.clear();
inputs.addAll(sortedList);
} catch (CircularDependencyException e) {
compiler.report(
JSError.make(CIRCULAR_DEPENDENCY_ERROR, e.getMessage()));
}
}
/**
* Returns the given collection of modules in topological order.
*
* Note that this will return the modules in the same order if they are
* already sorted, and in general, will only change the order as necessary to
* satisfy the ordering dependencies. This can be important for cases where
* the modules do not properly specify all dependencies.
*/
public static JSModule[] sortJsModules(Collection<JSModule> modules)
throws CircularDependencyException {
// Sort the JSModule in this order.
List<JSModule> sortedList = (new SortedDependencies<JSModule>(
Lists.newArrayList(modules))).getSortedList();
return sortedList.toArray(new JSModule[sortedList.size()]);
}
/**
* @param dep the depth to set
*/
public void setDepth(int dep) {
this.depth = dep;
}
/**
* @return the depth
*/
public int getDepth() {
return depth;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>;
} else if (scope != ref.scope) {
return true;
}
}
return false;
}
/**
* @param index The index into the references array to look for an
* assigning declaration.
*
* This is either the declaration if a value is assigned (such as
* "var a = 2", "function a()...", "... catch (a)...").
*/
private boolean isInitializingDeclarationAt(int index) {
Reference maybeInit = references.get(index);
if (maybeInit.isInitializingDeclaration()) {
// This is a declaration that represents the initial value.
// Specifically, var declarations without assignments such as "var a;"
// are not.
return true;
}
return false;
}
/**
* @param index The index into the references array to look for an
* initialized assignment reference. That is, an assignment immediately
* follow a variable declaration that itself does not initialize the
* variable.
*/
private boolean isInitializingAssignmentAt(int index) {
if (index < references.size() && index > 0) {
Reference maybeDecl = references.get(index-1);
if (maybeDecl.isVarDeclaration()) {
Preconditions.checkState(!maybeDecl.isInitializingDeclaration());
Reference maybeInit = references.get(index);
if (maybeInit.isSimpleAssignmentToName()) {
return true;
}
}
}
return false;
}
/**
* @return The reference that provides the value for the variable at the
* time of the first read, if known, otherwise null.
*
* This is either the variable declaration ("var a = ...") or first
* reference following the declaration if it is an assignment.
*/
Reference getInitializingReference() {
if (isInitializingDeclarationAt(0)) {
return references.get(0);
} else if (isInitializingAssignmentAt(1)) {
return references.get(1);
}
return null;
}
/**
* Constants are allowed to be defined after their first use.
*/
Reference getInitializingReferenceForConstants() {
int size = references.size();
for (int i = 0; i < size; i++) {
if (isInitializingDeclarationAt(i) || isInitializingAssignmentAt(i)) {
return references.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>;
}
}
/**
* A class common to all visitors that need to restrict the type based on
* some {@code typeof}-like condition being false. All base cases return
* their type. It is up to the subclasses to override the appropriate ones.
*/
abstract class RestrictByFalseTypeOfResultVisitor
extends RestrictByTypeOfResultVisitor {
@Override
protected JSType caseTopType(JSType topType) {
return topType;
}
public JSType caseNoObjectType() {
return getNativeType(NO_OBJECT_TYPE);
}
public JSType caseBooleanType() {
return getNativeType(BOOLEAN_TYPE);
}
public JSType caseFunctionType(FunctionType type) {
return type;
}
public JSType caseNullType() {
return getNativeType(NULL_TYPE);
}
public JSType caseNumberType() {
return getNativeType(NUMBER_TYPE);
}
public JSType caseObjectType(ObjectType type) {
return type;
}
public JSType caseStringType() {
return getNativeType(STRING_TYPE);
}
public JSType caseVoidType() {
return getNativeType(VOID_TYPE);
}
}
/**
* @see ChainableReverseAbstractInterpreter#getRestrictedByTypeOfResult
*/
private class RestrictByOneTypeOfResultVisitor
extends RestrictByTypeOfResultVisitor {
/**
* A value known to be equal or not equal to the result of the
* {@code typeOf} operation.
*/
private final String value;
/**
* {@code true} if the {@code typeOf} result is known to equal
* {@code value}; {@code false} if it is known <em>not</em> to equal
* {@code value}.
*/
private final boolean resultEqualsValue;
RestrictByOneTypeOfResultVisitor(String value, boolean resultEqualsValue) {
this.value = value;
this.resultEqualsValue = resultEqualsValue;
}
/**
* Computes whether the given result of a {@code typeof} operator matches
* expectations, i.e. whether a type that gives such a result should be
* kept.
*/
private boolean matchesExpectation(String result) {
return result.equals(value) == resultEqualsValue;
}
@Override
protected JSType caseTopType
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(JSType topType) {
JSType result = topType;
if (resultEqualsValue) {
JSType typeByName = getNativeTypeForTypeOf(value);
if (typeByName != null) {
result = typeByName;
}
}
return result;
}
public JSType caseNoObjectType() {
return (value.equals("object") || value.equals("function")) ==
resultEqualsValue ? getNativeType(NO_OBJECT_TYPE) : null;
}
public JSType caseBooleanType() {
return matchesExpectation("boolean") ? getNativeType(BOOLEAN_TYPE) : null;
}
public JSType caseFunctionType(FunctionType type) {
return matchesExpectation("function") ? type : null;
}
public JSType caseNullType() {
return matchesExpectation("object") ? getNativeType(NULL_TYPE) : null;
}
public JSType caseNumberType() {
return matchesExpectation("number") ? getNativeType(NUMBER_TYPE) : null;
}
public JSType caseObjectType(ObjectType type) {
if (value.equals("function")) {
JSType ctorType = getNativeType(U2U_CONSTRUCTOR_TYPE);
return resultEqualsValue && ctorType.isSubtype(type) ? ctorType : null;
}
return matchesExpectation("object") ? type : null;
}
public JSType caseStringType() {
return matchesExpectation("string") ? getNativeType(STRING_TYPE) : null;
}
public JSType caseVoidType() {
return matchesExpectation("undefined") ? getNativeType(VOID_TYPE) : null;
}
}
/**
* Returns a version of type where undefined is not present.
*/
final JSType getRestrictedWithoutUndefined(JSType type) {
return type == null ? null : type.visit(restrictUndefinedVisitor);
}
/**
* Returns a version of type where null is not present.
*/
final JSType getRestrictedWithoutNull(JSType type) {
return type == null ? null : type.visit(restrictNullVisitor);
}
/**
* Returns a version of {@code type} that is restricted by some knowledge
* about the result of the {@code typeof} operation.
* <p>
* The behavior of the {@code typeof} operator can be summarized
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> by the
* following table:
* <table>
* <tr><th>type</th><th>result</th></tr>
* <tr><td>{@code undefined}</td><td>"undefined"</td></tr>
* <tr><td>{@code null}</td><td>"object"</td></tr>
* <tr><td>{@code boolean}</td><td>"boolean"</td></tr>
* <tr><td>{@code number}</td><td>"number"</td></tr>
* <tr><td>{@code string}</td><td>"string"</td></tr>
* <tr><td>{@code Object} (which doesn't implement [[Call]])</td>
* <td>"object"</td></tr>
* <tr><td>{@code Object} (which implements [[Call]])</td>
* <td>"function"</td></tr>
* </table>
* @param type the type to restrict
* @param value A value known to be equal or not equal to the result of the
* {@code typeof} operation
* @param resultEqualsValue {@code true} if the {@code typeOf} result is known
* to equal {@code value}; {@code false} if it is known <em>not</em> to
* equal {@code value}
* @return the restricted type or null if no version of the type matches the
* restriction
*/
JSType getRestrictedByTypeOfResult(JSType type, String value,
boolean resultEqualsValue) {
if (type == null) {
if (resultEqualsValue) {
JSType result = getNativeTypeForTypeOf(value);
return result == null ? getNativeType(UNKNOWN_TYPE) : result;
} else {
return null;
}
}
return type.visit(
new RestrictByOneTypeOfResultVisitor(value, resultEqualsValue));
}
JSType getNativeType(JSTypeNative typeId) {
return typeRegistry.getNativeType(typeId);
}
/**
* If we definitely know what a type is based on the typeof result,
* return it. Otherwise, return null.
*
* The typeof operation in JS is poorly defined, and this function works
* for both the native typeof and goog.typeOf. It should not be
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> made public,
* because its semantics are informally defined, and would be wrong in
* the general case.
*/
private JSType getNativeTypeForTypeOf(String value) {
if (value.equals("number")) {
return getNativeType(NUMBER_TYPE);
} else if (value.equals("boolean")) {
return getNativeType(BOOLEAN_TYPE);
} else if (value.equals("string")) {
return getNativeType(STRING_TYPE);
} else if (value.equals("undefined")) {
return getNativeType(VOID_TYPE);
} else if (value.equals("function")) {
return getNativeType(U2U_CONSTRUCTOR_TYPE);
} else {
return null;
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> jsRoot) {
Preconditions.checkState(scopeCreator == null);
Preconditions.checkState(topScope == null);
Preconditions.checkState(jsRoot.getParent() != null);
Node externsAndJsRoot = jsRoot.getParent();
scopeCreator = new MemoizedScopeCreator(new TypedScopeCreator(compiler));
topScope = scopeCreator.createScope(externsAndJsRoot, null);
TypeInferencePass inference = new TypeInferencePass(compiler,
reverseInterpreter, topScope, scopeCreator);
inference.process(externsRoot, jsRoot);
process(externsRoot, jsRoot);
return topScope;
}
public void check(Node node, boolean externs) {
Preconditions.checkNotNull(node);
NodeTraversal t = new NodeTraversal(compiler, this, scopeCreator);
inExterns = externs;
t.traverseWithScope(node, topScope);
if (externs) {
inferJSDocInfo.process(node, null);
} else {
inferJSDocInfo.process(null, node);
}
}
private void checkNoTypeCheckSection(Node n, boolean enterSection) {
switch (n.getType()) {
case Token.SCRIPT:
case Token.BLOCK:
case Token.VAR:
case Token.FUNCTION:
case Token.ASSIGN:
JSDocInfo info = n.getJSDocInfo();
if (info != null && info.isNoTypeCheck()) {
if (enterSection) {
noTypeCheckSection++;
} else {
noTypeCheckSection--;
}
}
validator.setShouldReport(noTypeCheckSection == 0);
break;
}
}
private void report(NodeTraversal t, Node n, DiagnosticType diagnosticType,
String... arguments) {
if (noTypeCheckSection == 0) {
t.report(n, diagnosticType, arguments);
}
}
public boolean shouldTraverse(
NodeTraversal t, Node n, Node parent) {
checkNoTypeCheckSection(n, true);
switch (n.getType()) {
case Token.FUNCTION:
// normal type checking
final TypeCheck outerThis = this;
final Scope outerScope = t.getScope();
final FunctionType functionType = (FunctionType) n.getJSType();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
final String functionPrivateName = n.getFirstChild().getString();
if (functionPrivateName != null && functionPrivateName.length() > 0 &&
outerScope.isDeclared(functionPrivateName, false) &&
// Ideally, we would want to check whether the type in the scope
// differs from the type being defined, but then the extern
// redeclarations of built-in types generates spurious warnings.
!(outerScope.getVar(
functionPrivateName).getType() instanceof FunctionType)) {
report(t, n, FUNCTION_MASKS_VARIABLE, functionPrivateName);
}
// TODO(user): Only traverse the function's body. The function's
// name and arguments are traversed by the scope creator, and ideally
// should not be traversed by the type checker.
break;
}
return true;
}
/**
* This is the meat of the type checking. It is basically one big switch,
* with each case representing one type of parse tree node. The individual
* cases are usually pretty straightforward.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
* @param parent The parent of the node n.
*/
public void visit(NodeTraversal t, Node n, Node parent) {
JSType childType;
JSType leftType, rightType;
Node left, right;
// To be explicitly set to false if the node is not typeable.
boolean typeable = true;
switch (n.getType()) {
case Token.NAME:
typeable = visitName(t, n, parent);
break;
case Token.LP:
// If this is under a FUNCTION node, it is a parameter list and can be
// ignored here.
if (parent.getType() != Token.FUNCTION) {
ensureTyped(t, n, getJSType(n.getFirstChild()));
} else {
typeable = false;
}
break;
case Token.COMMA:
ensureTyped(t, n, getJSType(n.getLastChild()));
break;
case Token.TRUE:
case Token.FALSE:
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>), "increment/decrement");
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.NOT:
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.VOID:
ensureTyped(t, n, VOID_TYPE);
break;
case Token.TYPEOF:
ensureTyped(t, n, STRING_TYPE);
break;
case Token.BITNOT:
childType = getJSType(n.getFirstChild());
if (!childType.matchesInt32Context()) {
report(t, n, BIT_OPERATION, NodeUtil.opToStr(n.getType()),
childType.toString());
}
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.POS:
case Token.NEG:
left = n.getFirstChild();
validator.expectNumber(t, left, getJSType(left), "sign operator");
ensureTyped(t, n, NUMBER_TYPE);
break;
case Token.EQ:
case Token.NE: {
leftType = getJSType(n.getFirstChild());
rightType = getJSType(n.getLastChild());
JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined();
TernaryValue result =
leftTypeRestricted.testForEquality(rightTypeRestricted);
if (result != TernaryValue.UNKNOWN) {
if (n.getType() == Token.NE) {
result = result.not();
}
report(t, n, DETERMINISTIC_TEST, leftType.toString(),
rightType.toString(), result.toString());
}
ensureTyped(t, n, BOOLEAN_TYPE);
break;
}
case Token.SHEQ:
case Token.SHNE: {
leftType = getJSType(n.getFirstChild());
rightType = getJSType(n.getLastChild());
JSType leftTypeRestricted = leftType.restrictByNotNullOrUndefined();
JSType rightTypeRestricted = rightType.restrictByNotNullOrUndefined();
if (!leftTypeRestricted.canTestForShallowEqualityWith(
rightTypeRestricted)) {
report(t, n, DETERMINISTIC_TEST_NO_RESULT, leftType.toString(),
right
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Type.toString());
}
ensureTyped(t, n, BOOLEAN_TYPE);
break;
}
case Token.LT:
case Token.LE:
case Token.GT:
case Token.GE:
leftType = getJSType(n.getFirstChild());
rightType = getJSType(n.getLastChild());
if (rightType.isNumber()) {
validator.expectNumber(
t, n, leftType, "left side of numeric comparison");
} else if (leftType.isNumber()) {
validator.expectNumber(
t, n, rightType, "right side of numeric comparison");
} else if (leftType.matchesNumberContext() &&
rightType.matchesNumberContext()) {
// OK.
} else {
// Whether the comparison is numeric will be determined at runtime
// each time the expression is evaluated. Regardless, both operands
// should match a string context.
String message = "left side of comparison";
validator.expectString(t, n, leftType, message);
validator.expectNotNullOrUndefined(
t, n, leftType, message, getNativeType(STRING_TYPE));
message = "right side of comparison";
validator.expectString(t, n, rightType, message);
validator.expectNotNullOrUndefined(
t, n, rightType, message, getNativeType(STRING_TYPE));
}
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.IN:
left = n.getFirstChild();
right = n.getLastChild();
leftType = getJSType(left);
rightType = getJSType(right);
validator.expectObject(t, n, rightType, "'in' requires an object");
validator.expectString(t, left, leftType, "left side of 'in'");
ensureTyped(t, n, BOOLEAN_TYPE);
break;
case Token.INSTANCEOF:
left = n.getFirstChild();
right = n.getLastChild();
leftType = getJSType(left);
rightType = getJSType(right).restrictByNotNullOrUndefined();
validator.expectAnyObject(
t, left, leftType, "deterministic instanceof yields false");
validator.expectActualObject(
t, right, rightType, "instanceof requires an object");
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> object type it is referring to.
* @param t the traversal
* @param assign the assign node
* (<code>assign.getType() == Token.ASSIGN</code> is an implicit invariant)
*/
private void visitAssign(NodeTraversal t, Node assign) {
JSDocInfo info = assign.getJSDocInfo();
Node lvalue = assign.getFirstChild();
Node rvalue = assign.getLastChild();
if (lvalue.getType() == Token.GETPROP) {
Node object = lvalue.getFirstChild();
JSType objectJsType = getJSType(object);
String property = lvalue.getLastChild().getString();
// the first name in this getprop refers to an interface
// we perform checks in addition to the ones below
if (object.getType() == Token.GETPROP) {
JSType jsType = getJSType(object.getFirstChild());
if (jsType.isInterface() &&
object.getLastChild().getString().equals("prototype")) {
visitInterfaceGetprop(t, assign, object, property, lvalue, rvalue);
}
}
// /** @type ... */object.name = ...;
if (info != null && info.hasType()) {
visitAnnotatedAssignGetprop(t, assign,
info.getType().evaluate(t.getScope(), typeRegistry), object,
property, rvalue);
return;
}
// /** @enum ... */object.name = ...;
if (info != null && info.hasEnumParameterType()) {
checkEnumInitializer(
t, rvalue, info.getEnumParameterType().evaluate(
t.getScope(), typeRegistry));
return;
}
// object.prototype = ...;
if (property.equals("prototype")) {
if (objectJsType instanceof FunctionType) {
FunctionType functionType = (FunctionType) objectJsType;
if (functionType.isConstructor()) {
JSType rvalueType = rvalue.getJSType();
validator.expectObject(t, rvalue, rvalueType,
OVERRIDING_PROTOTYPE_WITH_NON_OBJECT);
}
} else {
// TODO(user): might want to flag that
}
return;
}
// object.prototype.property = ...;
if (object.getType() == Token.GETPROP
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>) {
Node object2 = object.getFirstChild();
String property2 = NodeUtil.getStringValue(object.getLastChild());
if ("prototype".equals(property2)) {
JSType jsType = object2.getJSType();
if (jsType instanceof FunctionType) {
FunctionType functionType = (FunctionType) jsType;
if (functionType.isConstructor() || functionType.isInterface()) {
checkDeclaredPropertyInheritance(
t, assign, functionType, property, info, getJSType(rvalue));
}
} else {
// TODO(user): might want to flag that
}
return;
}
}
// object.property = ...;
ObjectType type = ObjectType.cast(
objectJsType.restrictByNotNullOrUndefined());
if (type != null) {
if (type.hasProperty(property) &&
!type.isPropertyTypeInferred(property) &&
!propertyIsImplicitCast(type, property)) {
validator.expectCanAssignToPropertyOf(
t, assign, getJSType(rvalue),
type.getPropertyType(property), object, property);
}
return;
}
} else if (lvalue.getType() == Token.NAME) {
// variable with inferred type case
JSType rvalueType = getJSType(assign.getLastChild());
Var var = t.getScope().getVar(lvalue.getString());
if (var != null) {
if (var.isTypeInferred()) {
return;
}
}
}
// fall through case
JSType leftType = getJSType(lvalue);
Node rightChild = assign.getLastChild();
JSType rightType = getJSType(rightChild);
if (validator.expectCanAssignTo(
t, assign, rightType, leftType, "assignment")) {
ensureTyped(t, assign, rightType);
} else {
ensureTyped(t, assign);
}
}
/**
* Visits an object literal field definition <code>key : value</code>.
*
* If the <code>lvalue</code> is a prototype modification, we change the
* schema of the object type it is referring to.
*
* @param t the traversal
* @param key the assign node
*/
private void visitObjLitKey(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>NodeTraversal t, Node key, Node objlit) {
// TODO(johnlenz): Validate get and set function declarations are valid
// as is the functions can have "extraneous" bits.
// For getter and setter property definitions the
// rvalue type != the property type.
Node rvalue = key.getFirstChild();
JSType rightType = NodeUtil.getObjectLitKeyTypeFromValueType(
key, getJSType(rvalue));
if (rightType == null) {
rightType = getNativeType(UNKNOWN_TYPE);
}
Node owner = objlit;
// Validate value is assignable to the key type.
JSType keyType = getJSType(key);
boolean valid = validator.expectCanAssignToPropertyOf(t, key,
rightType, keyType,
owner, NodeUtil.getObjectLitKeyName(key));
if (valid) {
ensureTyped(t, key, rightType);
} else {
ensureTyped(t, key);
}
// Validate that the key type is assignable to the object property type.
// This is necessary as the objlit may have been cast to a non-literal
// object type.
// TODO(johnlenz): consider introducing a CAST node to the AST (or
// perhaps a parentheses node).
JSType objlitType = getJSType(objlit);
ObjectType type = ObjectType.cast(
objlitType.restrictByNotNullOrUndefined());
if (type != null) {
String property = NodeUtil.getObjectLitKeyName(key);
if (type.hasProperty(property) &&
!type.isPropertyTypeInferred(property) &&
!propertyIsImplicitCast(type, property)) {
validator.expectCanAssignToPropertyOf(
t, key, keyType,
type.getPropertyType(property), owner, property);
}
return;
}
}
/**
* Returns true if any type in the chain has an implictCast annotation for
* the given property.
*/
private boolean propertyIsImplicitCast(ObjectType type, String prop) {
for (; type != null; type = type.getImplicitPrototype()) {
JSDocInfo docInfo = type.getOwnPropertyJSDocInfo(prop);
if (docInfo != null && docInfo.isImplicitCast()) {
return true;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> return false;
}
/**
* Given a constructor type and a property name, check that the property has
* the JSDoc annotation @override iff the property is declared on a
* superclass. Several checks regarding inheritance correctness are also
* performed.
*/
private void checkDeclaredPropertyInheritance(
NodeTraversal t, Node n, FunctionType ctorType, String propertyName,
JSDocInfo info, JSType propertyType) {
// If the supertype doesn't resolve correctly, we've warned about this
// already.
if (hasUnknownOrEmptySupertype(ctorType)) {
return;
}
FunctionType superClass = ctorType.getSuperClassConstructor();
boolean superClassHasProperty = superClass != null &&
superClass.getPrototype().hasProperty(propertyName);
boolean declaredOverride = info != null && info.isOverride();
boolean foundInterfaceProperty = false;
if (ctorType.isConstructor()) {
for (JSType implementedInterface : ctorType.getImplementedInterfaces()) {
if (implementedInterface.isUnknownType() ||
implementedInterface.isEmptyType()) {
continue;
}
FunctionType interfaceType =
implementedInterface.toObjectType().getConstructor();
Preconditions.checkNotNull(interfaceType);
boolean interfaceHasProperty =
interfaceType.getPrototype().hasProperty(propertyName);
foundInterfaceProperty = foundInterfaceProperty || interfaceHasProperty;
if (reportMissingOverride.isOn() && !declaredOverride &&
interfaceHasProperty) {
// @override not present, but the property does override an interface
// property
compiler.report(t.makeError(n, reportMissingOverride,
HIDDEN_INTERFACE_PROPERTY, propertyName,
interfaceType.getTopMostDefiningType(propertyName).toString()));
}
}
}
if (!declaredOverride && !superClassHasProperty) {
// nothing to do here, it's just a plain new property
return;
}
JSType topInstanceType = superClassHasProperty ?
superClass.getTopMostDefiningType(propertyName) : null;
if (reportMissingOverride.isOn() && ctorType.isConstructor() &&
!declaredOverride && superClassHasProperty) {
// @override not present, but the property does override a superclass
// property
compiler.report(t.makeError(n, reportMissingOverride,
HIDDEN_SUPERCLASS_PROPERTY, propertyName
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>,
topInstanceType.toString()));
}
if (!declaredOverride) {
// there's no @override to check
return;
}
// @override is present and we have to check that it is ok
if (superClassHasProperty) {
// there is a superclass implementation
JSType superClassPropType =
superClass.getPrototype().getPropertyType(propertyName);
if (!propertyType.canAssignTo(superClassPropType)) {
compiler.report(
t.makeError(n, HIDDEN_SUPERCLASS_PROPERTY_MISMATCH,
propertyName, topInstanceType.toString(),
superClassPropType.toString(), propertyType.toString()));
}
} else if (!foundInterfaceProperty) {
// there is no superclass nor interface implementation
compiler.report(
t.makeError(n, UNKNOWN_OVERRIDE,
propertyName, ctorType.getInstanceType().toString()));
}
}
/**
* Given a constructor or an interface type, find out whether the unknown
* type is a supertype of the current type.
*/
private static boolean hasUnknownOrEmptySupertype(FunctionType ctor) {
Preconditions.checkArgument(ctor.isConstructor() || ctor.isInterface());
Preconditions.checkArgument(!ctor.isUnknownType());
// The type system should notice inheritance cycles on its own
// and break the cycle.
while (true) {
ObjectType maybeSuperInstanceType =
ctor.getPrototype().getImplicitPrototype();
if (maybeSuperInstanceType == null) {
return false;
}
if (maybeSuperInstanceType.isUnknownType() ||
maybeSuperInstanceType.isEmptyType()) {
return true;
}
ctor = maybeSuperInstanceType.getConstructor();
if (ctor == null) {
return false;
}
Preconditions.checkState(ctor.isConstructor() || ctor.isInterface());
}
}
/**
* Visits an ASSIGN node for cases such as
* <pre>
* interface.property2.property = ...;
* </pre>
*/
private void visitInterfaceGetprop(NodeTraversal t, Node assign, Node object,
String property, Node lvalue, Node rvalue) {
JSType rvalueType = getJSType(rvalue);
// Only 2 values are allowed for methods:
// goog.abstractMethod
// function () {};
//
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitGetElem(NodeTraversal t, Node n) {
Node left = n.getFirstChild();
Node right = n.getLastChild();
validator.expectIndexMatch(t, n, getJSType(left), getJSType(right));
ensureTyped(t, n);
}
/**
* Visits a VAR node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitVar(NodeTraversal t, Node n) {
// TODO(nicksantos): Fix this so that the doc info always shows up
// on the NAME node. We probably want to wait for the parser
// merge to fix this.
JSDocInfo varInfo = n.hasOneChild() ? n.getJSDocInfo() : null;
for (Node name : n.children()) {
Node value = name.getFirstChild();
// A null var would indicate a bug in the scope creation logic.
Var var = t.getScope().getVar(name.getString());
if (value != null) {
JSType valueType = getJSType(value);
JSType nameType = var.getType();
nameType = (nameType == null) ? getNativeType(UNKNOWN_TYPE) : nameType;
JSDocInfo info = name.getJSDocInfo();
if (info == null) {
info = varInfo;
}
if (info != null && info.hasEnumParameterType()) {
// var.getType() can never be null, this would indicate a bug in the
// scope creation logic.
checkEnumInitializer(
t, value,
info.getEnumParameterType().evaluate(t.getScope(), typeRegistry));
} else if (var.isTypeInferred()) {
ensureTyped(t, name, valueType);
} else {
validator.expectCanAssignTo(
t, value, valueType, nameType, "initializing variable");
}
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
/**
* Visits a NEW node.
*/
private void visitNew(NodeTraversal t, Node n) {
Node constructor = n.getFirstChild();
FunctionType type = getFunctionType(constructor);
if (type != null && type.isConstructor()) {
visitParameterList(t, n, type);
ensureTyped(t, n, type.getInstanceType());
} else {
// TODO(user): add support for namespaced objects.
if (constructor.getType() != Token.GETPROP) {
// TODO(user): make the constructor node have lineno/charno
// and use constructor for a more precise error indication.
// It seems that GETPROP nodes are missing this information.
Node line;
if (constructor.getLineno() < 0 || constructor.getCharno() < 0) {
line = n;
} else {
line = constructor;
}
report(t, line, NOT_A_CONSTRUCTOR);
}
ensureTyped(t, n);
}
}
/**
* Visits a {@link Token#FUNCTION} node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitFunction(NodeTraversal t, Node n) {
JSDocInfo info = n.getJSDocInfo();
FunctionType functionType = (FunctionType) n.getJSType();
String functionPrivateName = n.getFirstChild().getString();
if (functionType.isInterface() || functionType.isConstructor()) {
FunctionType baseConstructor = functionType.
getPrototype().getImplicitPrototype().getConstructor();
if (baseConstructor != null &&
baseConstructor != getNativeType(OBJECT_FUNCTION_TYPE) &&
(baseConstructor.isConstructor() && functionType.isInterface() ||
baseConstructor.isInterface() && functionType.isConstructor())) {
compiler.report(
t.makeError(n, CONFLICTING_EXTENDED_TYPE, functionPrivateName));
}
for (JSType baseInterface : functionType.getImplementedInterfaces()) {
boolean badImplementedType = false;
ObjectType baseInterfaceObj = ObjectType.cast(baseInterface);
if (baseInterfaceObj != null
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>) {
FunctionType interfaceConstructor =
baseInterfaceObj.getConstructor();
if (interfaceConstructor != null &&
!interfaceConstructor.isInterface()) {
badImplementedType = true;
}
} else {
badImplementedType = true;
}
if (badImplementedType) {
report(t, n, BAD_IMPLEMENTED_TYPE, functionPrivateName);
}
}
if (functionType.isConstructor()) {
validator.expectAllInterfaceProperties(t, n, functionType);
}
}
}
/**
* Visits a CALL node.
*
* @param t The node traversal object that supplies context, such as the
* scope chain to use in name lookups as well as error reporting.
* @param n The node being visited.
*/
private void visitCall(NodeTraversal t, Node n) {
Node child = n.getFirstChild();
JSType childType = getJSType(child).restrictByNotNullOrUndefined();
if (!childType.canBeCalled()) {
report(t, n, NOT_CALLABLE, childType.toString());
ensureTyped(t, n);
return;
}
// A couple of types can be called as if they were functions.
// If it is a function type, then validate parameters.
if (childType instanceof FunctionType) {
FunctionType functionType = (FunctionType) childType;
boolean isExtern = false;
JSDocInfo functionJSDocInfo = functionType.getJSDocInfo();
if(functionJSDocInfo != null) {
String sourceName = functionJSDocInfo.getSourceName();
CompilerInput functionSource = compiler.getInput(sourceName);
isExtern = functionSource.isExtern();
}
// Non-native constructors should not be called directly
// unless they specify a return type and are defined
// in an extern.
if (functionType.isConstructor() &&
!functionType.isNativeObjectType() &&
(functionType.getReturnType().isUnknownType() ||
functionType.getReturnType().isVoidType() ||
!isExtern)) {
report(t, n, CONSTRUCTOR_NOT_CALLABLE, childType.toString());
}
visitParameterList(t, n, functionType);
ensureTyped(t, n, functionType
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> it go.
if (function == null) {
return;
}
JSType jsType = getJSType(function);
if (jsType instanceof FunctionType) {
FunctionType functionType = (FunctionType) jsType;
JSType returnType = functionType.getReturnType();
// if no return type is specified, undefined must be returned
// (it's a void function)
if (returnType == null) {
returnType = getNativeType(VOID_TYPE);
}
// fetching the returned value's type
Node valueNode = n.getFirstChild();
JSType actualReturnType;
if (valueNode == null) {
actualReturnType = getNativeType(VOID_TYPE);
valueNode = n;
} else {
actualReturnType = getJSType(valueNode);
}
// verifying
validator.expectCanAssignTo(t, valueNode, actualReturnType, returnType,
"inconsistent return type");
}
}
/**
* This function unifies the type checking involved in the core binary
* operators and the corresponding assignment operators. The representation
* used internally is such that common code can handle both kinds of
* operators easily.
*
* @param op The operator.
* @param t The traversal object, needed to report errors.
* @param n The node being checked.
*/
private void visitBinaryOperator(int op, NodeTraversal t, Node n) {
Node left = n.getFirstChild();
JSType leftType = getJSType(left);
Node right = n.getLastChild();
JSType rightType = getJSType(right);
switch (op) {
case Token.ASSIGN_LSH:
case Token.ASSIGN_RSH:
case Token.LSH:
case Token.RSH:
case Token.ASSIGN_URSH:
case Token.URSH:
if (!leftType.matchesInt32Context()) {
report(t, left, BIT_OPERATION,
NodeUtil.opToStr(n.getType()), leftType.toString());
}
if (!rightType.matchesUint32Context()) {
report(t, right, BIT_OPERATION,
NodeUtil.opToStr(n.getType()), rightType.toString());
}
break;
case Token.ASSIGN_DIV:
case Token.ASSIGN_MOD:
case
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> Token.ASSIGN_MUL:
case Token.ASSIGN_SUB:
case Token.DIV:
case Token.MOD:
case Token.MUL:
case Token.SUB:
validator.expectNumber(t, left, leftType, "left operand");
validator.expectNumber(t, right, rightType, "right operand");
break;
case Token.ASSIGN_BITAND:
case Token.ASSIGN_BITXOR:
case Token.ASSIGN_BITOR:
case Token.BITAND:
case Token.BITXOR:
case Token.BITOR:
validator.expectBitwiseable(t, left, leftType,
"bad left operand to bitwise operator");
validator.expectBitwiseable(t, right, rightType,
"bad right operand to bitwise operator");
break;
case Token.ASSIGN_ADD:
case Token.ADD:
break;
default:
report(t, n, UNEXPECTED_TOKEN, Node.tokenToName(op));
}
ensureTyped(t, n);
}
/**
* <p>Checks the initializer of an enum. An enum can be initialized with an
* object literal whose values must be subtypes of the declared enum element
* type, or by copying another enum.</p>
*
* <p>In the case of an enum copy, we verify that the enum element type of the
* enum used for initialization is a subtype of the enum element type of
* the enum the value is being copied in.</p>
*
* <p>Examples:</p>
* <pre>var myEnum = {FOO: ..., BAR: ...};
* var myEnum = myOtherEnum;</pre>
*
* @param value the value used for initialization of the enum
* @param primitiveType The type of each element of the enum.
*/
private void checkEnumInitializer(
NodeTraversal t, Node value, JSType primitiveType) {
if (value.getType() == Token.OBJECTLIT) {
for (Node key = value.getFirstChild();
key != null; key = key.getNext()) {
Node propValue = key.getFirstChild();
// the value's type must be assignable to the enum's primitive type
validator.expectCanAssignTo(
t, propValue, getJSType(propValue), primitiveType,
"
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>element type must match enum's type");
}
} else if (value.getJSType() instanceof EnumType) {
// TODO(user): Remove the instanceof check in favor
// of a type.isEnumType() predicate. Currently, not all enum types are
// implemented by the EnumClass, e.g. the unknown type and the any
// type. The types need to be defined by interfaces such that an
// implementation can implement multiple types interface.
EnumType valueEnumType = (EnumType) value.getJSType();
JSType valueEnumPrimitiveType =
valueEnumType.getElementsType().getPrimitiveType();
validator.expectCanAssignTo(t, value, valueEnumPrimitiveType,
primitiveType, "incompatible enum element types");
} else {
// The error condition is handled in TypedScopeCreator.
}
}
/**
* This predicate is used to determine if the node represents an expression
* that is a Reference according to JavaScript definitions.
*
* @param n The node being checked.
* @return true if the sub-tree n is a reference, false otherwise.
*/
private static boolean isReference(Node n) {
switch (n.getType()) {
case Token.GETELEM:
case Token.GETPROP:
case Token.NAME:
return true;
default:
return false;
}
}
/**
* This method gets the JSType from the Node argument and verifies that it is
* present.
*/
private JSType getJSType(Node n) {
JSType jsType = n.getJSType();
if (jsType == null) {
// TODO(nicksantos): This branch indicates a compiler bug, not worthy of
// halting the compilation but we should log this and analyze to track
// down why it happens. This is not critical and will be resolved over
// time as the type checker is extended.
return getNativeType(UNKNOWN_TYPE);
} else {
return jsType;
}
}
/**
* Gets the type of the node or {@code null} if the node's type is not a
* function.
*/
private FunctionType getFunctionType(Node n) {
JSType type = getJSType(n).restrictByNotNullOrUndefined();
if (type.isUnknownType()) {
return type
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Registry.getNativeFunctionType(U2U_CONSTRUCTOR_TYPE);
} else if (type instanceof FunctionType) {
return (FunctionType) type;
} else {
return null;
}
}
// TODO(nicksantos): TypeCheck should never be attaching types to nodes.
// All types should be attached by TypeInference. This is not true today
// for legacy reasons. There are a number of places where TypeInference
// doesn't attach a type, as a signal to TypeCheck that it needs to check
// that node's type.
/**
* Ensure that the given node has a type. If it does not have one,
* attach the UNKNOWN_TYPE.
*/
private void ensureTyped(NodeTraversal t, Node n) {
ensureTyped(t, n, getNativeType(UNKNOWN_TYPE));
}
private void ensureTyped(NodeTraversal t, Node n, JSTypeNative type) {
ensureTyped(t, n, getNativeType(type));
}
/**
* Enforces type casts, and ensures the node is typed.
*
* A cast in the way that we use it in JSDoc annotations never
* alters the generated code and therefore never can induce any runtime
* operation. What this means is that a 'cast' is really just a compile
* time constraint on the underlying value. In the future, we may add
* support for run-time casts for compiled tests.
*
* To ensure some shred of sanity, we enforce the notion that the
* type you are casting to may only meaningfully be a narrower type
* than the underlying declared type. We also invalidate optimizations
* on bad type casts.
*
* @param t The traversal object needed to report errors.
* @param n The node getting a type assigned to it.
* @param type The type to be assigned.
*/
private void ensureTyped(NodeTraversal t, Node n, JSType type) {
// Make sure FUNCTION nodes always get function type.
Preconditions.checkState(n.getType() != Token.FUNCTION ||
type instanceof FunctionType ||
type.isUnknownType());
JSDocInfo info = n.getJSDocInfo();
if (info != null) {
if (info.hasType()) {
JSType infoType =
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
return assignment.getLastChild();
}
}
/**
* Represents member declarations using a object literal.
* Example: var x = { e : function() { } };
*/
static final class ObjectLiteralPropertyDefinition extends Definition {
private final Node literal;
private final Node name;
private final Node value;
ObjectLiteralPropertyDefinition(Node lit, Node name, Node value,
boolean isExtern) {
super(isExtern);
this.literal = lit;
this.name = name;
this.value = value;
}
@Override
public void performRemove() {
literal.removeChild(name);
}
@Override
public Node getLValue() {
// TODO(user) revisit: object literal definitions are an example
// of definitions whose lhs doesn't correspond to a node that
// exists in the AST. We will have to change the return type of
// getLValue sooner or later in order to provide this added
// flexibility.
switch (name.getType()) {
case Token.SET:
case Token.GET:
case Token.STRING:
// TODO(johnlenz): return a GETELEM for quoted strings.
return new Node(Token.GETPROP,
new Node(Token.OBJECTLIT),
name.cloneNode());
case Token.NUMBER:
return new Node(Token.GETELEM,
new Node(Token.OBJECTLIT),
name.cloneNode());
default:
throw new IllegalStateException("unexpected");
}
}
@Override
public Node getRValue() {
return value;
}
}
/**
* Represents a VAR declaration with an assignment.
*/
static final class VarDefinition extends Definition {
private final Node name;
VarDefinition(Node node, boolean inExterns) {
super(inExterns);
Preconditions.checkArgument(NodeUtil.isVarDeclaration(node));
Preconditions.checkArgument(node.hasChildren(),
"VAR Declaration of " + node.getString() +
"should be assigned a value.");
name = node;
}
@Override
public void performRemove() {
Node var = name.getParent();
Preconditions.checkState(var.getFirstChild() == var.getLastChild(),
"AST should be normalized first");
Node parent = var.getParent();
Node rValue = name.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> properties of this type are also NoResolved types,
* and comparisons to other types always have an unknown result.
*
* @author nicksantos@google.com (Nick Santos)
*/
class NoResolvedType extends NoType {
private static final long serialVersionUID = 1L;
NoResolvedType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNoResolvedType() {
return true;
}
@Override
public boolean isNoType() {
return false;
}
@Override
public JSType getPropertyType(String propertyName) {
return getNativeType(JSTypeNative.CHECKED_UNKNOWN_TYPE);
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
} else {
return !that.isNoType();
}
}
@Override
public String toString() {
return "NoResolvedType";
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> source = getSource();
String sourceExcerpt = source == null ? null :
excerpt.get(
source, error.sourceName, error.lineNumber, excerptFormatter);
// formatting the message
StringBuilder b = new StringBuilder();
if (error.sourceName != null) {
b.append(error.sourceName);
if (error.lineNumber > 0) {
b.append(':');
b.append(error.lineNumber);
}
b.append(": ");
}
b.append(getLevelName(warning ? CheckLevel.WARNING : CheckLevel.ERROR));
b.append(" - ");
b.append(error.description);
b.append('\n');
if (sourceExcerpt != null) {
b.append(sourceExcerpt);
b.append('\n');
int charno = error.getCharno();
// padding equal to the excerpt and arrow at the end
if (excerpt.equals(LINE)
&& 0 <= charno && charno < sourceExcerpt.length()) {
for (int i = 0; i < charno; i++) {
char c = sourceExcerpt.charAt(i);
if (Character.isWhitespace(c)) {
b.append(c);
} else {
b.append(' ');
}
}
b.append("^\n");
}
}
return b.toString();
}
/**
* Formats a region by appending line numbers in front, e.g.
* <pre> 9| if (foo) {
* 10| alert('bar');
* 11| }</pre>
* and return line excerpt without any modification.
*/
static class LineNumberingFormatter implements ExcerptFormatter {
public String formatLine(String line, int lineNumber) {
return line;
}
public String formatRegion(Region region) {
if (region == null) {
return null;
}
String code = region.getSourceExcerpt();
if (code.length() == 0) {
return null;
}
// max length of the number display
int numberLength = Integer.toString(region.getEndingLineNumber())
.length();
// formatting
StringBuilder builder = new StringBuilder(code.length() * 2);
int
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> start = 0;
int end = code.indexOf('\n', start);
int lineNumber = region.getBeginningLineNumber();
while (start >= 0) {
// line extraction
String line;
if (end < 0) {
line = code.substring(start);
if (line.length() == 0) {
return builder.substring(0, builder.length() - 1);
}
} else {
line = code.substring(start, end);
}
builder.append(" ");
// nice spaces for the line number
int spaces = numberLength - Integer.toString(lineNumber).length();
builder.append(Strings.repeat(" ", spaces));
builder.append(lineNumber);
builder.append("| ");
// end & update
if (end < 0) {
builder.append(line);
start = -1;
} else {
builder.append(line);
builder.append('\n');
start = end + 1;
end = code.indexOf('\n', start);
lineNumber++;
}
}
return builder.toString();
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Prototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyTypeInferred(property);
}
// property does not exist
return false;
}
return p.inferred;
}
@Override
public JSType getPropertyType(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.type;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.getPropertyType(propertyName);
}
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
@Override
public boolean isPropertyInExterns(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.inExterns;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.isPropertyInExterns(propertyName);
}
return false;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
boolean inExterns, Node propertyNode) {
if (hasOwnDeclaredProperty(name)) {
return false;
}
properties.put(name, new Property(type, inferred, inExterns, propertyNode));
return true;
}
@Override
public Node getPropertyNode(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.propertyNode;
}
ObjectType implicitPrototype = getImplicitPrototype();
if (implicitPrototype != null) {
return implicitPrototype.getPropertyNode(propertyName);
}
return null;
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
Property p = properties.get(propertyName);
if (p != null) {
return p.docInfo;
}
return null;
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
if (info != null) {
if (!properties.containsKey(propertyName)) {
// If docInfo was attached, but the type of the property
// was not defined anywhere, then we consider this an explicit
// declaration of the property.
defineInferredProperty
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(propertyName, getPropertyType(propertyName),
inExterns, null);
}
// The prototype property is not represented as a normal Property.
// We probably don't want to attach any JSDoc to it anyway.
Property property = properties.get(propertyName);
if (property != null) {
property.docInfo = info;
}
}
}
@Override
public boolean matchesNumberContext() {
return isNumberObjectType() || isDateType() || isBooleanObjectType() ||
isStringObjectType() || hasOverridenNativeProperty("valueOf");
}
@Override
public boolean matchesStringContext() {
return isTheObjectType() || isStringObjectType() || isDateType() ||
isRegexpType() || isArrayType() || isNumberObjectType() ||
isBooleanObjectType() || hasOverridenNativeProperty("toString");
}
/**
* Given the name of a native object property, checks whether the property is
* present on the object and different from the native one.
*/
private boolean hasOverridenNativeProperty(String propertyName) {
if (isNative()) {
return false;
}
JSType propertyType = getPropertyType(propertyName);
ObjectType nativeType =
this.isFunctionType() ?
registry.getNativeObjectType(JSTypeNative.FUNCTION_PROTOTYPE) :
registry.getNativeObjectType(JSTypeNative.OBJECT_PROTOTYPE);
JSType nativePropertyType = nativeType.getPropertyType(propertyName);
return propertyType != nativePropertyType;
}
@Override
public JSType unboxesTo() {
if (isStringObjectType()) {
return getNativeType(JSTypeNative.STRING_TYPE);
} else if (isBooleanObjectType()) {
return getNativeType(JSTypeNative.BOOLEAN_TYPE);
} else if (isNumberObjectType()) {
return getNativeType(JSTypeNative.NUMBER_TYPE);
} else {
return super.unboxesTo();
}
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean canBeCalled() {
return isRegexpType();
}
/**
* Whether this represents a native type (such as Object, Date,
* RegExp, etc.).
*/
boolean isNative() {
return nativeType;
}
@Override
public String toString() {
if (
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>hasReferenceName()) {
return getReferenceName();
} else if (prettyPrint) {
// Use a tree set so that the properties are sorted.
Set<String> propertyNames = Sets.newTreeSet();
for (ObjectType current = this;
current != null && !current.isNativeObjectType() &&
propertyNames.size() <= MAX_PRETTY_PRINTED_PROPERTIES;
current = current.getImplicitPrototype()) {
propertyNames.addAll(current.getOwnPropertyNames());
}
StringBuilder sb = new StringBuilder();
sb.append("{");
int i = 0;
for (String property : propertyNames) {
if (i > 0) {
sb.append(", ");
}
sb.append(property);
sb.append(": ");
sb.append(getPropertyType(property).toString());
++i;
if (i == MAX_PRETTY_PRINTED_PROPERTIES) {
sb.append(", ...");
break;
}
}
sb.append("}");
return sb.toString();
} else {
return "{...}";
}
}
void setPrettyPrint(boolean prettyPrint) {
this.prettyPrint = prettyPrint;
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
public ObjectType getImplicitPrototype() {
return implicitPrototypeFallback;
}
/**
* This should only be reset on the FunctionPrototypeType, only to fix an
* incorrectly established prototype chain due to the user having a mismatch
* in super class declaration, and only before properties on that type are
* processed.
*/
final void setImplicitPrototype(ObjectType implicitPrototype) {
checkState(!hasCachedValues());
this.implicitPrototypeFallback = implicitPrototype;
}
@Override
public String getReferenceName() {
if (className != null) {
return className;
} else {
return null;
}
}
@Override
public boolean hasReferenceName() {
return className != null;
}
@Override
public boolean isSubtype(JSType that) {
if (JSType.isSubtype(this, that)) {
return true;
}
// Union types
if (that instanceof UnionType) {
// The static {@code JSType.isSubtype} check already decomposed
// union types, so we don't need
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> to check those again.
return false;
}
// record types
if (that instanceof RecordType) {
return RecordType.isSubtype(this, (RecordType) that);
}
// Interfaces
// Find all the interfaces implemented by this class and compare each one
// to the interface instance.
ObjectType thatObj = that.toObjectType();
ObjectType thatCtor = thatObj == null ? null : thatObj.getConstructor();
if (thatCtor != null && thatCtor.isInterface()) {
Iterable<ObjectType> thisInterfaces = getCtorImplementedInterfaces();
for (ObjectType thisInterface : thisInterfaces) {
if (thisInterface.isSubtype(that)) {
return true;
}
}
}
// other prototype based objects
if (that != null) {
if (isUnknownType() || implicitPrototypeChainIsUnknown()) {
// If unsure, say 'yes', to avoid spurious warnings.
// TODO(user): resolve the prototype chain completely in all cases,
// to avoid guessing.
return true;
}
return this.isImplicitPrototype(thatObj);
}
return false;
}
private boolean implicitPrototypeChainIsUnknown() {
ObjectType p = getImplicitPrototype();
while (p != null) {
if (p.isUnknownType()) {
return true;
}
p = p.getImplicitPrototype();
}
return false;
}
private static final class Property implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Property's type.
*/
private JSType type;
/**
* Whether the property's type is inferred.
*/
private final boolean inferred;
/**
* Whether the property is defined in the externs.
*/
private final boolean inExterns;
/**
* The node corresponding to this property, e.g., a GETPROP node that
* declares this property.
*/
private final Node propertyNode;
/** The JSDocInfo for this property. */
private JSDocInfo docInfo = null;
private Property(JSType type, boolean inferred, boolean inExterns, Node propertyNode) {
this.type = type;
this.inferred = inferred;
this.inExterns = inExterns;
this.propertyNode = propertyNode;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> */
void endPass() {
Preconditions.checkState(currentTracer != null,
"Tracer should not be null at the end of a pass.");
stopTracer(currentTracer, currentPassName);
String passToCheck = currentPassName;
currentPassName = null;
currentTracer = null;
maybeSanityCheck();
}
/**
* Returns a new tracer for the given pass name.
*/
Tracer newTracer(String passName) {
String comment = passName
+ (recentChange.hasCodeChanged() ? " on recently changed AST" : "");
if (options.tracer.isOn()) {
tracker.recordPassStart(passName);
}
return new Tracer("Compiler", comment);
}
void stopTracer(Tracer t, String passName) {
long result = t.stop();
if (options.tracer.isOn()) {
tracker.recordPassStop(passName, result);
}
}
/**
* Returns the result of the compilation.
*/
public Result getResult() {
PassConfig.State state = getPassConfig().getIntermediateState();
return new Result(getErrors(), getWarnings(), debugLog.toString(),
state.variableMap, state.propertyMap,
state.anonymousFunctionNameMap, state.stringMap, functionInformationMap,
sourceMap, externExports, state.cssNames, state.idGeneratorMap);
}
/**
* Returns an array constructed from errors + temporary warnings.
*/
public JSError[] getMessages() {
return getErrors();
}
/**
* Returns the array of errors (never null).
*/
public JSError[] getErrors() {
return errorManager.getErrors();
}
/**
* Returns the array of warnings (never null).
*/
public JSError[] getWarnings() {
return errorManager.getWarnings();
}
/**
* Returns the root node of the AST, which includes both externs and source.
*/
public Node getRoot() {
return externAndJsRoot;
}
/**
* Creates a new id for making unique names.
*/
private int nextUniqueNameId() {
return uniqueNameId++;
}
/**
* Resets the unique name id counter
*/
@VisibleForTesting
void resetUniqueNameId() {
uniqueNameId = 0;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
// Inputs can have a null AST during initial parse.
if (n == null) {
continue;
}
if (n.getJSDocInfo() != null) {
JSDocInfo info = n.getJSDocInfo();
if (info.isExterns()) {
// If the input file is explicitly marked as an externs file, then
// assume the programmer made a mistake and throw it into
// the externs pile anyways.
externsRoot.addChildToBack(n);
input.setIsExtern(true);
input.getModule().remove(input);
externs.add(input);
staleInputs = true;
} else if (info.isNoCompile()) {
input.getModule().remove(input);
staleInputs = true;
}
}
}
if (staleInputs) {
fillEmptyModules(modules);
rebuildInputsFromModules();
}
// Build the AST.
for (CompilerInput input : inputs) {
Node n = input.getAstRoot(this);
if (n == null) {
continue;
}
if (devMode) {
runSanityCheck();
if (hasErrors()) {
return null;
}
}
if (options.sourceMapOutputPath != null ||
options.nameReferenceReportPath != null) {
// Annotate the nodes in the tree with information from the
// input file. This information is used to construct the SourceMap.
SourceInformationAnnotator sia =
new SourceInformationAnnotator(
input.getName(), options.devMode != DevMode.OFF);
NodeTraversal.traverse(this, n, sia);
}
jsRoot.addChildToBack(n);
}
return externAndJsRoot;
} finally {
stopTracer(tracer, "parseInputs");
}
}
public Node parse(JSSourceFile file) {
initCompilerOptionsIfTesting();
addToDebugLog("Parsing: " + file.getName());
return new JsAst(file).getAstRoot(this);
}
@Override
Node parseSyntheticCode(String js) {
CompilerInput input = new CompilerInput(
JSSourceFile.fromCode(" [synthetic] ", js));
inputsByName.put(input.getName(), input);
return input.get
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>AstRoot(this);
}
void initCompilerOptionsIfTesting() {
if (options == null) {
// initialization for tests that don't initialize the compiler
// by the normal mechanisms.
initOptions(new CompilerOptions());
}
}
@Override
Node parseSyntheticCode(String fileName, String js) {
initCompilerOptionsIfTesting();
return parse(JSSourceFile.fromCode(fileName, js));
}
@Override
Node parseTestCode(String js) {
initCompilerOptionsIfTesting();
CompilerInput input = new CompilerInput(
JSSourceFile.fromCode(" [testcode] ", js));
if (inputsByName == null) {
inputsByName = Maps.newHashMap();
}
inputsByName.put(input.getName(), input);
return input.getAstRoot(this);
}
@Override
ErrorReporter getDefaultErrorReporter() {
return defaultErrorReporter;
}
//------------------------------------------------------------------------
// Convert back to source code
//------------------------------------------------------------------------
/**
* Converts the main parse tree back to js code.
*/
public String toSource() {
return runInCompilerThread(new Callable<String>() {
public String call() throws Exception {
Tracer tracer = newTracer("toSource");
try {
CodeBuilder cb = new CodeBuilder();
if (jsRoot != null) {
int i = 0;
for (Node scriptNode = jsRoot.getFirstChild();
scriptNode != null;
scriptNode = scriptNode.getNext()) {
toSource(cb, i++, scriptNode);
}
}
return cb.toString();
} finally {
stopTracer(tracer, "toSource");
}
}
});
}
/**
* Converts the parse tree for each input back to js code.
*/
public String[] toSourceArray() {
return runInCompilerThread(new Callable<String[]>() {
public String[] call() throws Exception {
Tracer tracer = newTracer("toSourceArray");
try {
int numInputs = inputs.size();
String[] sources = new String[numInputs];
CodeBuilder cb = new CodeBuilder();
for (int i = 0; i < numInputs; i++) {
Node scriptNode = inputs.get(i).getAstRoot(Compiler.this);
cb.reset();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
toSource(cb, i, scriptNode);
sources[i] = cb.toString();
}
return sources;
} finally {
stopTracer(tracer, "toSourceArray");
}
}
});
}
/**
* Converts the parse tree for a module back to js code.
*/
public String toSource(final JSModule module) {
return runInCompilerThread(new Callable<String>() {
public String call() throws Exception {
List<CompilerInput> inputs = module.getInputs();
int numInputs = inputs.size();
if (numInputs == 0) {
return "";
}
CodeBuilder cb = new CodeBuilder();
for (int i = 0; i < numInputs; i++) {
Node scriptNode = inputs.get(i).getAstRoot(Compiler.this);
if (scriptNode == null) {
throw new IllegalArgumentException(
"Bad module: " + module.getName());
}
toSource(cb, i, scriptNode);
}
return cb.toString();
}
});
}
/**
* Converts the parse tree for each input in a module back to js code.
*/
public String[] toSourceArray(final JSModule module) {
return runInCompilerThread(new Callable<String[]>() {
public String[] call() throws Exception {
List<CompilerInput> inputs = module.getInputs();
int numInputs = inputs.size();
if (numInputs == 0) {
return new String[0];
}
String[] sources = new String[numInputs];
CodeBuilder cb = new CodeBuilder();
for (int i = 0; i < numInputs; i++) {
Node scriptNode = inputs.get(i).getAstRoot(Compiler.this);
if (scriptNode == null) {
throw new IllegalArgumentException(
"Bad module input: " + inputs.get(i).getName());
}
cb.reset();
toSource(cb, i, scriptNode);
sources[i] = cb.toString();
}
return sources;
}
});
}
/**
* Writes out js code from a root node. If printing input delimiters, this
* method will attach a comment to the start of the text indicating which
* input the output derived from. If there were any preserve annotations
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
* within the root's source, they will also be printed in a block comment
* at the beginning of the output.
*/
public void toSource(final CodeBuilder cb,
final int inputSeqNum,
final Node root) {
runInCompilerThread(new Callable<Void>() {
public Void call() throws Exception {
if (options.printInputDelimiter) {
if ((cb.getLength() > 0) && !cb.endsWith("\n")) {
cb.append("\n"); // Make sure that the label starts on a new line
}
Preconditions.checkState(root.getType() == Token.SCRIPT);
String delimiter = options.inputDelimiter;
String sourceName = (String)root.getProp(Node.SOURCENAME_PROP);
Preconditions.checkState(sourceName != null);
Preconditions.checkState(!sourceName.isEmpty());
delimiter = delimiter.replaceAll("%name%", sourceName)
.replaceAll("%num%", String.valueOf(inputSeqNum));
cb.append(delimiter)
.append("\n");
}
if (root.getJSDocInfo() != null &&
root.getJSDocInfo().getLicense() != null) {
cb.append("/*\n")
.append(root.getJSDocInfo().getLicense())
.append("*/\n");
}
// If there is a valid source map, then indicate to it that the current
// root node's mappings are offset by the given string builder buffer.
if (options.sourceMapOutputPath != null) {
sourceMap.setStartingPosition(
cb.getLineIndex(), cb.getColumnIndex());
}
String code = toSource(root, sourceMap);
if (!code.isEmpty()) {
cb.append(code);
// In order to avoid parse ambiguity when files are concatenated
// together, all files should end in a semi-colon. Do a quick
// heuristic check if there's an obvious semi-colon already there.
int length = code.length();
char lastChar = code.charAt(length - 1);
char secondLastChar = length >= 2 ?
code.charAt(length - 2) : '\0';
boolean hasSemiColon = lastChar == ';' ||
(lastChar == '\n' && secondLastChar == ';');
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
if (!hasSemiColon) {
cb.append(";");
}
}
return null;
}
});
}
/**
* Generates JavaScript source code for an AST, doesn't generate source
* map info.
*/
@Override
String toSource(Node n) {
initCompilerOptionsIfTesting();
return toSource(n, null);
}
/**
* Generates JavaScript source code for an AST.
*/
private String toSource(Node n, SourceMap sourceMap) {
CodePrinter.Builder builder = new CodePrinter.Builder(n);
builder.setPrettyPrint(options.prettyPrint);
builder.setLineBreak(options.lineBreak);
builder.setSourceMap(sourceMap);
builder.setSourceMapDetailLevel(options.sourceMapDetailLevel);
builder.setTagAsStrict(
options.getLanguageOut() == LanguageMode.ECMASCRIPT5_STRICT);
builder.setLineLengthThreshold(options.lineLengthThreshold);
Charset charset = options.outputCharset != null ?
Charset.forName(options.outputCharset) : null;
builder.setOutputCharset(charset);
return builder.build();
}
/**
* Stores a buffer of text to which more can be appended. This is just like a
* StringBuilder except that we also track the number of lines.
*/
public static class CodeBuilder {
private final StringBuilder sb = new StringBuilder();
private int lineCount = 0;
private int colCount = 0;
/** Removes all text, but leaves the line count unchanged. */
void reset() {
sb.setLength(0);
}
/** Appends the given string to the text buffer. */
CodeBuilder append(String str) {
sb.append(str);
// Adjust the line and column information for the new text.
int index = -1;
int lastIndex = index;
while ((index = str.indexOf('\n', index + 1)) >= 0) {
++lineCount;
lastIndex = index;
}
if (lastIndex == -1) {
// No new lines, append the new characters added.
colCount += str.length();
} else {
colCount = str.length() - (lastIndex + 1);
}
return this;
}
/** Returns all text
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> in the text buffer. */
@Override
public String toString() {
return sb.toString();
}
/** Returns the length of the text buffer. */
public int getLength() {
return sb.length();
}
/** Returns the (zero-based) index of the last line in the text buffer. */
int getLineIndex() {
return lineCount;
}
/** Returns the (zero-based) index of the last column in the text buffer. */
int getColumnIndex() {
return colCount;
}
/** Determines whether the text ends with the given suffix. */
boolean endsWith(String suffix) {
return (sb.length() > suffix.length())
&& suffix.equals(sb.substring(sb.length() - suffix.length()));
}
}
//------------------------------------------------------------------------
// Optimizations
//------------------------------------------------------------------------
public void optimize() {
// Ideally, this pass should be the first pass run, however:
// 1) VariableReferenceCheck reports unexpected warnings if Normalize
// is done first.
// 2) ReplaceMessages, stripCode, and potentially custom passes rely on
// unmodified local names.
normalize();
PhaseOptimizer phaseOptimizer = new PhaseOptimizer(this, tracker);
if (options.devMode == DevMode.EVERY_PASS) {
phaseOptimizer.setSanityCheck(sanityCheck);
}
phaseOptimizer.consume(getPassConfig().getOptimizations());
phaseOptimizer.process(externsRoot, jsRoot);
if (hasErrors()) {
return;
}
}
@Override
void setCssRenamingMap(CssRenamingMap map) {
options.cssRenamingMap = map;
}
@Override
CssRenamingMap getCssRenamingMap() {
return options.cssRenamingMap;
}
/**
* Reprocesses the current defines over the AST. This is used by GwtCompiler
* to generate N outputs for different targets from the same (checked) AST.
* For each target, we apply the target-specific defines by calling
* {@code processDefines} and then {@code optimize} to optimize the AST
* specifically for that target.
*/
public void processDefines() {
(new DefaultPassConfig(options)).processDefines.create(this)
.process(externsRoot, jsRoot
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>details);
}
@Override public final String getMessage()
{
String details = details();
if (sourceName == null || lineNumber <= 0) {
return details;
}
StringBuilder buf = new StringBuilder(details);
buf.append(" (");
if (sourceName != null) {
buf.append(sourceName);
}
if (lineNumber > 0) {
buf.append('#');
buf.append(lineNumber);
}
buf.append(')');
return buf.toString();
}
public String details()
{
return super.getMessage();
}
/**
* Get the uri of the script source containing the error, or null
* if that information is not available.
*/
public final String sourceName()
{
return sourceName;
}
/**
* Initialize the uri of the script source containing the error.
*
* @param sourceName the uri of the script source reponsible for the error.
* It should not be <tt>null</tt>.
*
* @throws IllegalStateException if the method is called more then once.
*/
public final void initSourceName(String sourceName)
{
if (sourceName == null) throw new IllegalArgumentException();
if (this.sourceName != null) throw new IllegalStateException();
this.sourceName = sourceName;
}
/**
* Returns the line number of the statement causing the error,
* or zero if not available.
*/
public final int lineNumber()
{
return lineNumber;
}
/**
* Initialize the line number of the script statement causing the error.
*
* @param lineNumber the line number in the script source.
* It should be positive number.
*
* @throws IllegalStateException if the method is called more then once.
*/
public final void initLineNumber(int lineNumber)
{
if (lineNumber <= 0) throw new IllegalArgumentException(String.valueOf(lineNumber));
if (this.lineNumber > 0) throw new IllegalStateException();
this.lineNumber = lineNumber;
}
/**
* The column number of the location of the error, or zero if unknown.
*/
public final int columnNumber()
{
return columnNumber;
}
/**
* Initialize the column number of the script statement causing the error.
*
* @param columnNumber the
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
return name.endsWith(".js");
}
});
}
/**
* Get a string representing the script stack of this exception.
* If optimization is enabled, this corresponds to all java stack elements
* with a source name matching the <code>filter</code>.
* @param filter the file name filter to determine whether a file is a
* script file
* @return a script stack dump
* @since 1.6R6
*/
public String getScriptStackTrace(FilenameFilter filter)
{
// The real Rhino code here has been removed.
return "<No stack trace available>";
}
@Override public void printStackTrace(PrintWriter s)
{
if (interpreterStackInfo == null) {
super.printStackTrace(s);
} else {
s.print(generateStackTrace());
}
}
@Override public void printStackTrace(PrintStream s)
{
if (interpreterStackInfo == null) {
super.printStackTrace(s);
} else {
s.print(generateStackTrace());
}
}
private String sourceName;
private int lineNumber;
private String lineSource;
private int columnNumber;
Object interpreterStackInfo;
int[] interpreterLineData;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>rhino.Node;
import java.util.Set;
/**
* Object type.
*
* In JavaScript, all object types have properties, and each of those
* properties has a type. Property types may be DECLARED, INFERRED, or
* UNKNOWN.
*
* DECLARED properties have an explicit type annotation, as in:
* <code>
* /xx @type {number} x/
* Foo.prototype.bar = 1;
* </code>
* This property may only hold number values, and an assignment to any
* other type of value is an error.
*
* INFERRED properties do not have an explicit type annotation. Rather,
* we try to find all the possible types that this property can hold.
* <code>
* Foo.prototype.bar = 1;
* </code>
* If the programmer assigns other types of values to this property,
* the property will take on the union of all these types.
*
* UNKNOWN properties are properties on the UNKNOWN type. The UNKNOWN
* type has all properties, but we do not know whether they are
* declared or inferred.
*
*/
public abstract class ObjectType extends JSType {
private boolean visited;
private JSDocInfo docInfo = null;
private boolean unknown = true;
ObjectType(JSTypeRegistry registry) {
super(registry);
}
/**
* Gets the declared default element type.
* @see ParameterizedType
*/
public JSType getParameterType() {
return null;
}
/**
* Gets the declared default index type.
* @see IndexedType
*/
public JSType getIndexType() {
return null;
}
/**
* Gets the docInfo for this type.
*/
@Override public JSDocInfo getJSDocInfo() {
if (docInfo != null) {
return docInfo;
} else if (getImplicitPrototype() != null) {
return getImplicitPrototype().getJSDocInfo();
} else {
return super.getJSDocInfo();
}
}
/**
* Sets the docInfo for this type from the given
* {@link JSDocInfo}. The {@code JSDocInfo} may be {@code null}.
*/
public void setJSDocInfo(JSD
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ocInfo info) {
docInfo = info;
}
/**
* Detects a cycle in the implicit prototype chain. This method accesses
* the {@link #getImplicitPrototype()} method and must therefore be
* invoked only after the object is sufficiently initialized to respond to
* calls to this method.<p>
*
* The method is not thread safe.<p>
*
* @return True iff an implicit prototype cycle was detected.
*/
final boolean detectImplicitPrototypeCycle() {
// detecting cycle
this.visited = true;
ObjectType p = getImplicitPrototype();
while (p != null) {
if (p.visited) {
return true;
} else {
p.visited = true;
}
p = p.getImplicitPrototype();
}
// clean up
p = this;
do {
p.visited = false;
p = p.getImplicitPrototype();
} while (p != null);
return false;
}
/**
* Gets the reference name for this object. This includes named types
* like constructors, prototypes, and enums. It notably does not include
* literal types like strings and booleans and structural types.
* @return the object's name or {@code null} if this is an anonymous
* object
*/
public abstract String getReferenceName();
/**
* Due to the complexity of some of our internal type systems, sometimes
* we have different types constructed by the same constructor.
* In other parts of the type system, these are called delegates.
* We construct these types by appending suffixes to the constructor name.
*
* The normalized reference name does not have these suffixes, and as such,
* recollapses these implicit types back to their real type.
*/
public String getNormalizedReferenceName() {
String name = getReferenceName();
if (name != null) {
int pos = name.indexOf("(");
if (pos != -1) {
return name.substring(0, pos);
}
}
return name;
}
@Override
public String getDisplayName() {
return getNormalizedReferenceName();
}
/**
* Creates a suffix for a proxy delegate.
* @see #getNormalizedReferenceName
*/
public static String createDelegateSuffix(String suffix) {
return "("
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> definition of the specified property.
* This could be the node corresponding to declaration of the property or the
* node corresponding to the first reference to this property, e.g.,
* "this.propertyName" in a constructor. Note this is mainly intended to be
* an estimate of where in the source code a property is defined. Sometime
* the returned node is not even part of the global AST but in the AST of the
* JsDoc that defines a type.
*
* @param propertyName the name of the property
* @return the {@code Node} corresponding to the property or null.
*/
public Node getPropertyNode(String propertyName) {
return null;
}
/**
* Gets the docInfo on the specified property on this type. This should not
* be done implemented recursively, as you generally need to know exactly on
* which type in the prototype chain the JSDocInfo exists.
*/
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return null;
}
/**
* Sets the docInfo for the specified property from the
* {@link JSDocInfo} on its definition.
* @param info {@code JSDocInfo} for the property definition. May be
* {@code null}.
* @param inExterns {@code true} if this property was defined in an externs
* file. TightenTypes assumes that any function passed to an externs
* property could be called, so setting this incorrectly could result
* in live code being removed.
*/
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
// by default, do nothing
}
@Override
public JSType findPropertyType(String propertyName) {
return hasProperty(propertyName) ?
getPropertyType(propertyName) : null;
}
/**
* Gets the property type of the property whose name is given. If the
* underlying object does not have this property, the Unknown type is
* returned to indicate that no information is available on this property.
*
* @return the property's type or {@link UnknownType}. This method never
* returns {@code null}.
*/
public abstract JSType getPropertyType(String propertyName);
/**
* Checks whether the property whose name is given is present on the
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Name, int lineno, int charno) {
super(registry, registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
Preconditions.checkNotNull(reference);
this.reference = reference;
this.sourceName = sourceName;
this.lineno = lineno;
this.charno = charno;
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns, Node propertyNode) {
if (!isResolved()) {
// If this is an unresolved object type, we need to save all its
// properties and define them when it is resolved.
if (propertyContinuations == null) {
propertyContinuations = Lists.newArrayList();
}
propertyContinuations.add(
new PropertyContinuation(
propertyName, type, inferred, inExterns, propertyNode));
return true;
} else {
return super.defineProperty(
propertyName, type, inferred, inExterns, propertyNode);
}
}
private void finishPropertyContinuations() {
ObjectType referencedObjType = getReferencedObjTypeInternal();
if (referencedObjType != null && !referencedObjType.isUnknownType()) {
if (propertyContinuations != null) {
for (PropertyContinuation c : propertyContinuations) {
c.commit(this);
}
}
}
propertyContinuations = null;
}
/** Returns the type to which this refers (which is unknown if unresolved). */
public JSType getReferencedType() {
return getReferencedTypeInternal();
}
@Override
public String getReferenceName() {
return reference;
}
@Override
public String toString() {
return reference;
}
@Override
public boolean hasReferenceName() {
return true;
}
@Override
boolean isNamedType() {
return true;
}
@Override
public boolean isNominalType() {
return true;
}
/**
* Two named types are equivalent if they are the same {@code
* ObjectType} object. This is complicated by the fact that isEquivalent
* is sometimes called before we have a chance to resolve the type
* names.
*
* @return {@code true} iff {@code that} == {@code this} or {@code that}
* is a {@link NamedType} whose reference is the same as ours,
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS><JSType> enclosing) {
JSType value = lookupViaProperties(t, enclosing);
// last component of the chain
if ((value instanceof FunctionType) &&
(value.isConstructor() || value.isInterface())) {
FunctionType functionType = (FunctionType) value;
setReferencedAndResolvedType(
functionType.getInstanceType(), t, enclosing);
} else if (value instanceof EnumType) {
setReferencedAndResolvedType(
((EnumType) value).getElementsType(), t, enclosing);
} else {
// We've been running into issues where people forward-declare
// non-named types. (This is legitimate...our dependency management
// code doubles as our forward-declaration code.)
//
// So if the type does resolve to an actual value, but it's not named,
// then don't respect the forward declaration.
handleUnresolvedType(t, value == null || value.isUnknownType());
}
}
/**
* Resolves a type by looking up its first component in the scope, and
* subsequent components as properties. The scope must have been fully
* parsed and a symbol table constructed.
* @return The type of the symbol, or null if the type could not be found.
*/
private JSType lookupViaProperties( ErrorReporter t,
StaticScope<JSType> enclosing) {
String[] componentNames = reference.split("\\.", -1);
if (componentNames[0].length() == 0) {
return null;
}
StaticSlot<JSType> slot = enclosing.getSlot(componentNames[0]);
if (slot == null) {
return null;
}
// If the first component has a type of 'Unknown', then any type
// names using it should be regarded as silently 'Unknown' rather than be
// noisy about it.
JSType slotType = slot.getType();
if (slotType == null || slotType.isAllType() || slotType.isNoType()) {
return null;
}
JSType value = getTypedefType(t, slot, componentNames[0]);
if (value == null) {
return null;
}
// resolving component by component
for (int i = 1; i < componentNames.length; i++) {
ObjectType parent
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Class = ObjectType.cast(value);
if (parentClass == null) {
return null;
}
if (componentNames[i].length() == 0) {
return null;
}
value = parentClass.getPropertyType(componentNames[i]);
}
return value;
}
private void setReferencedAndResolvedType(JSType type, ErrorReporter t,
StaticScope<JSType> enclosing) {
if (validator != null) {
validator.apply(type);
}
setReferencedType(type);
checkEnumElementCycle(t);
setResolvedTypeInternal(getReferencedType());
}
private void handleTypeCycle(ErrorReporter t) {
setReferencedType(
registry.getNativeObjectType(JSTypeNative.UNKNOWN_TYPE));
t.warning("Cycle detected in inheritance chain of type " + reference,
sourceName, lineno, null, charno);
setResolvedTypeInternal(getReferencedType());
}
private void checkEnumElementCycle(ErrorReporter t) {
JSType referencedType = getReferencedType();
if (referencedType instanceof EnumElementType &&
((EnumElementType) referencedType).getPrimitiveType() == this) {
handleTypeCycle(t);
}
}
// Warns about this type being unresolved iff it's not a forward-declared
// type name.
private void handleUnresolvedType(
ErrorReporter t, boolean ignoreForwardReferencedTypes) {
if (registry.isLastGeneration()) {
boolean isForwardDeclared =
ignoreForwardReferencedTypes &&
registry.isForwardDeclaredType(reference);
if (!isForwardDeclared && registry.isLastGeneration()) {
t.warning("Bad type annotation. Unknown type " + reference,
sourceName, lineno, null, charno);
} else {
setReferencedType(
registry.getNativeObjectType(
JSTypeNative.NO_RESOLVED_TYPE));
if (registry.isLastGeneration() && validator != null) {
validator.apply(getReferencedType());
}
}
setResolvedTypeInternal(getReferencedType());
} else {
setResolvedTypeInternal(this);
}
}
JSType getTypedefType(ErrorReporter t, StaticSlot<JSType> slot, String name) {
JSType type = slot.getType();
if (type != null) {
return type;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> This is invalid, but allow it so the checks can catch it.
return;
}
declareVar(n.getFirstChild());
return; // should not examine function's children
case Token.CATCH:
Preconditions.checkState(n.getChildCount() == 2);
Preconditions.checkState(n.getFirstChild().getType() == Token.NAME);
// the first child is the catch var and the third child
// is the code block
final Node var = n.getFirstChild();
final Node block = var.getNext();
declareVar(var);
scanVars(block, n);
return; // only one child to scan
case Token.SCRIPT:
sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
break;
}
// Variables can only occur in statement-level nodes, so
// we only need to traverse children in a couple special cases.
if (NodeUtil.isControlStructure(n) || NodeUtil.isStatementBlock(n)) {
for (Node child = n.getFirstChild();
child != null;) {
Node next = child.getNext();
scanVars(child, n);
child = next;
}
}
}
/**
* Interface for injectable duplicate handling.
*/
interface RedeclarationHandler {
void onRedeclaration(
Scope s, String name, Node n, CompilerInput input);
}
/**
* The default handler for duplicate declarations.
*/
private class DefaultRedeclarationHandler implements RedeclarationHandler {
public void onRedeclaration(
Scope s, String name, Node n, CompilerInput input) {
Node parent = n.getParent();
// Don't allow multiple variables to be declared at the top level scope
if (scope.isGlobal()) {
Scope.Var origVar = scope.getVar(name);
Node origParent = origVar.getParentNode();
if (origParent.getType() == Token.CATCH &&
parent.getType() == Token.CATCH) {
// Okay, both are 'catch(x)' variables.
return;
}
boolean allowDupe = false;
JSDocInfo info = n.getJSDocInfo();
if (info == null) {
info = parent.getJSDocInfo();
}
allowDupe =
info != null && info.get
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Name)) {
return lhsOfDotName + delimiter;
} else {
return lhsOfDotName + delimiter + rhsOfDotName;
}
case Token.GETELEM:
Node outsideBrackets = node.getFirstChild();
Node insideBrackets = outsideBrackets.getNext();
String nameOutsideBrackets = getName(outsideBrackets);
String nameInsideBrackets = getName(insideBrackets);
if ("prototype".equals(nameInsideBrackets)) {
return nameOutsideBrackets + delimiter;
} else {
return nameOutsideBrackets + delimiter + nameInsideBrackets;
}
case Token.NAME:
return node.getString();
case Token.STRING:
return TokenStream.isJSIdentifier(node.getString()) ?
node.getString() : ("__" + nextUniqueInt++);
case Token.NUMBER:
return NodeUtil.getStringValue(node);
case Token.THIS:
return "this";
case Token.CALL:
return getName(node.getFirstChild());
default:
StringBuilder sb = new StringBuilder();
for (Node child = node.getFirstChild(); child != null;
child = child.getNext()) {
if (sb.length() > 0) {
sb.append(delimiter);
}
sb.append(getName(child));
}
return sb.toString();
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> assign {@code x} a type within the {@code f(x)}
* call. Since it has no possible type, we assign {@code x} the NoType,
* so that {@code f(x)} is legal no matter what the type of {@code f}'s
* first argument is.
*
* @see <a href="http://en.wikipedia.org/wiki/Bottom_type">Bottom types</a>
*/
public class NoType extends NoObjectType {
private static final long serialVersionUID = 1L;
NoType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNoObjectType() {
return false;
}
@Override
public boolean isNoType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean isSubtype(JSType that) {
return true;
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.EMPTY;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNoType();
}
@Override
public String toString() {
return "None";
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>type);
// If this is a prototype property, then we want to skip assignments
// to the instance type as well. These assignments are not usually
// seen in the extern code itself, so we must handle them here.
if ((type = typeSystem.getInstanceFromPrototype(type)) != null) {
prop.getTypes().add(type);
prop.typesToSkip.add(type);
}
}
}
}
}
/**
* Traverses the tree, building a map from field names to Nodes for all
* fields that can be renamed.
*/
private class FindRenameableProperties extends AbstractScopingCallback {
@Override
public void visit(NodeTraversal t, Node n, Node parent) {
if (n.getType() == Token.GETPROP) {
handleGetProp(t, n);
} else if (n.getType() == Token.OBJECTLIT) {
handleObjectLit(t, n);
}
}
/**
* Processes a GETPROP node.
*/
private void handleGetProp(NodeTraversal t, Node n) {
String name = n.getLastChild().getString();
T type = typeSystem.getType(getScope(), n.getFirstChild(), name);
Property prop = getProperty(name);
if (!prop.scheduleRenaming(n.getLastChild(),
processProperty(t, prop, type, null))) {
if (showInvalidationWarnings) {
compiler.report(JSError.make(
t.getSourceName(), n, Warnings.INVALIDATION, name,
(type == null ? "null" : type.toString()), n.toString()));
}
}
}
/**
* Processes a OBJECTLIT node.
*/
private void handleObjectLit(NodeTraversal t, Node n) {
Node child = n.getFirstChild();
while (child != null) {
// Maybe STRING, NUMBER, GET, SET
if (child.getType() != Token.NUMBER) {
// We should never see a mix of numbers and strings.
String name = child.getString();
T type = typeSystem.getType(getScope(), n, name);
Property prop = getProperty(name);
if (!prop.scheduleRenaming(child,
processProperty(t, prop, type, null))) {
if (showInvalidationWarnings)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
compiler.report(JSError.make(
t.getSourceName(), child, Warnings.INVALIDATION, name,
(type == null ? "null" : type.toString()), n.toString()));
}
}
}
child = child.getNext();
}
}
/**
* Processes a property, adding it to the list of properties to rename.
* @return a representative type for the property reference, which will be
* the highest type on the prototype chain of the provided type. In the
* case of a union type, it will be the highest type on the prototype
* chain of one of the members of the union.
*/
private T processProperty(
NodeTraversal t, Property prop, T type, T relatedType) {
type = typeSystem.restrictByNotNullOrUndefined(type);
if (prop.skipRenaming || typeSystem.isInvalidatingType(type)) {
return null;
}
Iterable<T> alternatives = typeSystem.getTypeAlternatives(type);
if (alternatives != null) {
T firstType = relatedType;
for (T subType : alternatives) {
T lastType = processProperty(t, prop, subType, firstType);
if (lastType != null) {
firstType = firstType == null ? lastType : firstType;
}
}
return firstType;
} else {
T topType = typeSystem.getTypeWithProperty(prop.name, type);
if (typeSystem.isInvalidatingType(topType)) {
return null;
}
prop.addType(type, topType, relatedType);
return topType;
}
}
}
/** Renames all properties with references on more than one type. */
void renameProperties() {
int propsRenamed = 0, propsSkipped = 0, instancesRenamed = 0,
instancesSkipped = 0, singleTypeProps = 0;
for (Property prop : properties.values()) {
if (prop.shouldRename()) {
Map<T, String> propNames = buildPropNames(prop.getTypes(), prop.name);
++propsRenamed;
prop.expandTypesToSkip();
UnionFind<T> types = prop.getTypes();
for (Node node : prop.renameNodes)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
T rootType = prop.rootTypes.get(node);
if (prop.shouldRename(rootType)) {
String newName = propNames.get(rootType);
node.setString(newName);
compiler.reportCodeChange();
++instancesRenamed;
} else {
++instancesSkipped;
}
}
} else {
if (prop.skipRenaming) {
++propsSkipped;
} else {
++singleTypeProps;
}
}
}
logger.info("Renamed " + instancesRenamed + " instances of "
+ propsRenamed + " properties.");
logger.info("Skipped renaming " + instancesSkipped + " invalidated "
+ "properties, " + propsSkipped + " instances of properties "
+ "that were skipped for specific types and " + singleTypeProps
+ " properties that were referenced from only one type.");
}
/**
* Chooses a name to use for renaming in each equivalence class and maps
* each type in that class to it.
*/
private Map<T, String> buildPropNames(UnionFind<T> types, String name) {
Map<T, String> names = Maps.newHashMap();
for (Set<T> set : types.allEquivalenceClasses()) {
checkState(!set.isEmpty());
String typeName = null;
for (T type : set) {
if (typeName == null || type.toString().compareTo(typeName) < 0) {
typeName = type.toString();
}
}
String newName;
if ("{...}".equals(typeName)) {
newName = name;
} else {
newName = typeName.replaceAll("[^\\w$]", "_") + "$" + name;
}
for (T type : set) {
names.put(type, newName);
}
}
return names;
}
/** Returns a map from field name to types for which it will be renamed. */
Multimap<String, Collection<T>> getRenamedTypesForTesting() {
Multimap<String, Collection<T>> ret = HashMultimap.create();
for (Map.Entry<String, Property> entry: properties.entrySet()) {
Property prop = entry.getValue();
if (!prop.skipRenaming) {
for (Collection<T> c : prop.getTypes
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> node;
}
@Override
public List<GraphNode<N, E>> getNeighborNodes(N value) {
UndiGraphNode<N, E> uNode = getUndirectedGraphNode(value);
List<GraphNode<N, E>> nodeList = Lists.newArrayList();
for (Iterator<GraphNode<N, E>> i = getNeighborNodesIterator(value);
i.hasNext();) {
nodeList.add(i.next());
}
return nodeList;
}
@Override
public Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value) {
UndiGraphNode<N, E> uNode = getUndirectedGraphNode(value);
Preconditions.checkNotNull(uNode, value + " should be in the graph.");
return ((LinkedUndirectedGraphNode<N, E>) uNode).neighborIterator();
}
@SuppressWarnings("unchecked")
@Override
public List<UndiGraphEdge<N, E>> getUndirectedGraphEdges(N n1, N n2) {
UndiGraphNode<N, E> dNode1 = nodes.get(n1);
if (dNode1 == null) {
return null;
}
UndiGraphNode<N, E> dNode2 = nodes.get(n2);
if (dNode2 == null) {
return null;
}
List<UndiGraphEdge<N, E>> edges = Lists.newArrayList();
for (UndiGraphEdge<N, E> outEdge : dNode1.getNeighborEdges()) {
if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
edges.add(outEdge);
}
}
return edges;
}
@Override
public UndiGraphNode<N, E> getUndirectedGraphNode(N nodeValue) {
return nodes.get(nodeValue);
}
@Override
public Collection<UndiGraphNode<N, E>> getUndirectedGraphNodes() {
return Collections.<UndiGraphNode<N, E>>unmodifiableCollection(
nodes.values());
}
@Override
public GraphNode<N, E> createNode(N value) {
return createUndirectedGraphNode(value);
}
@Override
public List
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS><GraphEdge<N, E>> getEdges(N n1, N n2) {
return Collections.<GraphEdge<N, E>>unmodifiableList(
getUndirectedGraphEdges(n1, n2));
}
@Override
public GraphEdge<N, E> getFirstEdge(N n1, N n2) {
UndiGraphNode<N, E> dNode1 = getNodeOrFail(n1);
UndiGraphNode<N, E> dNode2 = getNodeOrFail(n2);
for (UndiGraphEdge<N, E> outEdge : dNode1.getNeighborEdges()) {
if (outEdge.getNodeA() == dNode2 || outEdge.getNodeB() == dNode2) {
return outEdge;
}
}
return null;
}
@Override
public GraphNode<N, E> getNode(N value) {
return getUndirectedGraphNode(value);
}
@Override
public boolean isConnected(N n1, N n2) {
return isConnected(n1, Predicates.<E>alwaysTrue(), n2);
}
@Override
public boolean isConnected(N n1, E e, N n2) {
return isConnected(n1, Predicates.<E>equalTo(e), n2);
}
private boolean isConnected(N n1, Predicate<E> edgePredicate, N n2) {
UndiGraphNode<N, E> dNode1 = nodes.get(n1);
if (dNode1 == null) {
return false;
}
UndiGraphNode<N, E> dNode2 = nodes.get(n2);
if (dNode2 == null) {
return false;
}
for (UndiGraphEdge<N, E> outEdge : dNode1.getNeighborEdges()) {
if ((outEdge.getNodeA() == dNode1 && outEdge.getNodeB() == dNode2) ||
(outEdge.getNodeA() == dNode2 && outEdge.getNodeB() == dNode1)) {
if (edgePredicate.apply(outEdge.getValue())) {
return true;
}
}
}
return false;
}
@Override
public List<GraphvizEdge> getGraphvizEdges() {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
List<GraphvizEdge> edgeList = Lists.newArrayList();
for (LinkedUndirectedGraphNode<N, E> node : nodes.values()) {
for (UndiGraphEdge<N, E> edge : node.getNeighborEdges()) {
if (edge.getNodeA() == node) {
edgeList.add((GraphvizEdge) edge);
}
}
}
return edgeList;
}
@Override
public String getName() {
return "LinkedUndirectedGraph";
}
@Override
public List<GraphvizNode> getGraphvizNodes() {
List<GraphvizNode> nodeList =
Lists.newArrayListWithCapacity(nodes.size());
for (LinkedUndirectedGraphNode<N, E> node : nodes.values()) {
nodeList.add(node);
}
return nodeList;
}
@Override
public boolean isDirected() {
return false;
}
@Override
public Collection<GraphNode<N, E>> getNodes() {
return Collections.<GraphNode<N, E>> unmodifiableCollection(nodes.values());
}
@SuppressWarnings("unchecked")
@Override
public List<GraphEdge<N, E>> getEdges() {
List<GraphEdge<N, E>> result = Lists.newArrayList();
for (LinkedUndirectedGraphNode<N, E> node : nodes.values()) {
for (UndiGraphEdge<N, E> edge : node.getNeighborEdges()) {
if (edge.getNodeA() == node) {
result.add(edge);
}
}
}
return result;
}
@Override
public int getNodeDegree(N value) {
UndiGraphNode<N, E> uNode = getUndirectedGraphNode(value);
if (uNode == null) {
throw new IllegalArgumentException(value + " not found in graph");
}
return uNode.getNeighborEdges().size();
}
/**
* An undirected graph node that stores outgoing edges and incoming edges as
* an list within the node itself.
*/
static class LinkedUndirectedGraphNode<N, E> implements UndiGraphNode<N, E>,
GraphvizNode {
private List<UndiGraphEdge<N, E>> neighborList =
Lists.newArrayList();
private final N value;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
LinkedUndirectedGraphNode(N nodeValue) {
this.value = nodeValue;
}
@Override
public List<UndiGraphEdge<N, E>> getNeighborEdges() {
return neighborList;
}
public Iterator<UndiGraphEdge<N, E>> getNeighborEdgesIterator() {
return neighborList.iterator();
}
@Override
public <A extends Annotation> A getAnnotation() {
throw new UnsupportedOperationException(
"Graph initialized with node annotations turned off");
}
@Override
public void setAnnotation(Annotation data) {
throw new UnsupportedOperationException(
"Graph initialized with node annotations turned off");
}
@Override
public N getValue() {
return value;
}
@Override
public String getColor() {
return "white";
}
@Override
public String getId() {
return "LDN" + hashCode();
}
@Override
public String getLabel() {
return value != null ? value.toString() : "null";
}
public Iterator<GraphNode<N, E>> neighborIterator() {
return new NeighborIterator();
}
private class NeighborIterator implements Iterator<GraphNode<N, E>> {
private final Iterator<UndiGraphEdge<N, E>> edgeIterator =
neighborList.iterator();
@Override
public boolean hasNext() {
return edgeIterator.hasNext();
}
@Override
public GraphNode<N, E> next() {
UndiGraphEdge<N, E> edge = edgeIterator.next();
if (edge.getNodeA() == LinkedUndirectedGraphNode.this) {
return edge.getNodeB();
} else {
return edge.getNodeA();
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("Remove not supported.");
}
}
}
/**
* An undirected graph node with annotations.
*/
static class AnnotatedLinkedUndirectedGraphNode<N, E>
extends LinkedUndirectedGraphNode<N, E> {
protected Annotation annotation;
AnnotatedLinkedUndirectedGraphNode(N nodeValue) {
super(nodeValue);
}
@SuppressWarnings("unchecked")
@Override
public <A extends Annotation> A getAnnotation() {
return (A) annotation;
}
@Override
public void setAnnotation(Annotation data)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
annotation = data;
}
}
/**
* An undirected graph edge that stores two nodes at each edge.
*/
static class LinkedUndirectedGraphEdge<N, E> implements UndiGraphEdge<N, E>,
GraphvizEdge {
private UndiGraphNode<N, E> nodeA;
private UndiGraphNode<N, E> nodeB;
protected final E value;
LinkedUndirectedGraphEdge(UndiGraphNode<N, E> nodeA, E edgeValue,
UndiGraphNode<N, E> nodeB) {
this.value = edgeValue;
this.nodeA = nodeA;
this.nodeB = nodeB;
}
@Override
public E getValue() {
return value;
}
@Override
public GraphNode<N, E> getNodeA() {
return nodeA;
}
@Override
public GraphNode<N, E> getNodeB() {
return nodeB;
}
@Override
public <A extends Annotation> A getAnnotation() {
throw new UnsupportedOperationException(
"Graph initialized with edge annotations turned off");
}
@Override
public void setAnnotation(Annotation data) {
throw new UnsupportedOperationException(
"Graph initialized with edge annotations turned off");
}
@Override
public String getColor() {
return "black";
}
@Override
public String getLabel() {
return value != null ? value.toString() : "null";
}
@SuppressWarnings("unchecked")
@Override
public String getNode1Id() {
return ((LinkedUndirectedGraphNode<N, E>) nodeA).getId();
}
@SuppressWarnings("unchecked")
@Override
public String getNode2Id() {
return ((LinkedUndirectedGraphNode<N, E>) nodeB).getId();
}
@Override
public String toString() {
return nodeA.toString() + " -- " + nodeB.toString();
}
}
/**
* An annotated undirected graph edge..
*/
static class AnnotatedLinkedUndirectedGraphEdge<N, E>
extends LinkedUndirectedGraphEdge<N, E> {
protected Annotation annotation;
AnnotatedLinkedUndirectedGraphEdge(
UndiGraphNode<N, E> nodeA, E edgeValue,
UndiGraphNode<N, E
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
if (superConstructor != null) {
ObjectType superInstance =
funType.getSuperClassConstructor().getInstanceType();
if (!superInstance.toString().equals("Object")) {
sb.append(" * @extends {" + superInstance + "}\n");
}
}
// Avoid duplicates, add implemented type to a set first
Set<String> interfaces = Sets.newTreeSet();
for (ObjectType interfaze : funType.getImplementedInterfaces()) {
interfaces.add(interfaze.toString());
}
for (String interfaze : interfaces) {
sb.append(" * @implements {" + interfaze + "}\n");
}
if (funType.isConstructor()) {
sb.append(" * @constructor\n");
} else if (funType.isInterface()) {
sb.append(" * @interface\n");
}
}
if (fnNode != null && fnNode.getBooleanProp(Node.IS_DISPATCHER)) {
sb.append(" * @javadispatch\n");
}
sb.append(" */\n");
return sb.toString();
}
/**
* Creates a JSDoc-suitable String representation the type of a parameter.
*
* @param parameterNode The parameter node.
*/
private String getParameterNodeJSDocType(Node parameterNode) {
JSType parameterType = parameterNode.getJSType();
String typeString;
// Emit unknown types as '*' (AllType) since '?' (UnknownType) is not
// a valid JSDoc type.
if (parameterType.isUnknownType()) {
typeString = "*";
} else {
// Fix-up optional and vararg parameters to match JSDoc type language
if (parameterNode.isOptionalArg()) {
typeString = parameterType.restrictByNotNullOrUndefined() + "=";
} else if (parameterNode.isVarArgs()) {
typeString = "..." + parameterType.restrictByNotNullOrUndefined();
} else {
typeString = parameterType.toString();
}
}
return typeString;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> (NodeUtil.isFunctionDeclaration(n)) {
Node nameNode = n.getFirstChild();
renamer.addDeclaredName(nameNode.getString());
}
for (Node c = n.getFirstChild(); c != null; c = c.getNext()) {
findDeclaredNames(c, n, renamer);
}
}
}
/**
* Declared names renaming policy interface.
*/
interface Renamer {
/**
* Called when a declared name is found in the local current scope.
*/
void addDeclaredName(String name);
/**
* @return A replacement name, null if oldName is unknown or should not
* be replaced.
*/
String getReplacementName(String oldName);
/**
* @return Whether the constant-ness of a name should be removed.
*/
boolean stripConstIfReplaced();
/**
* @return A Renamer for a scope within the scope of the current Renamer.
*/
Renamer forChildScope();
}
/**
* Inverts the transformation by {@link ContextualRenamer}, when possible.
*/
static class ContextualRenameInverter
implements ScopedCallback, CompilerPass {
private final AbstractCompiler compiler;
// The set of names referenced in the current scope.
private Set<String> referencedNames = ImmutableSet.of();
// Stack reference sets.
private Deque<Set<String>> referenceStack = new ArrayDeque<Set<String>>();
// Name are globally unique initially, so we don't need a per-scope map.
private Map<String, List<Node>> nameMap = Maps.newHashMap();
private ContextualRenameInverter(AbstractCompiler compiler) {
this.compiler = compiler;
}
public void process(Node externs, Node js) {
NodeTraversal.traverse(compiler, js, this);
}
public static String getOrginalName(String name) {
int index = indexOfSeparator(name);
return (index == -1) ? name : name.substring(0, index);
}
private static int indexOfSeparator(String name) {
return name.lastIndexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR);
}
private boolean containsSeparator(String name) {
return name.indexOf(ContextualRenamer.UNIQUE_ID_SEPARATOR) != -1;
}
/**
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Property>(FREQUENCY_COMPARATOR);
propsByFreq.addAll(propertyMap.values());
generateNames(propsByFreq, reservedNames);
// Update the string nodes.
boolean changed = false;
for (Node n : stringNodesToRename) {
String oldName = n.getString();
Property p = propertyMap.get(oldName);
if (p != null && p.newName != null) {
Preconditions.checkState(oldName.equals(p.oldName));
n.setString(p.newName);
changed = changed || !p.newName.equals(oldName);
}
}
// Update the call nodes.
for (Node n : callNodeToParentMap.keySet()) {
Node parent = callNodeToParentMap.get(n);
Node firstArg = n.getFirstChild().getNext();
StringBuilder sb = new StringBuilder();
for (String oldName : firstArg.getString().split("[.]")) {
Property p = propertyMap.get(oldName);
String replacement;
if (p != null && p.newName != null) {
Preconditions.checkState(oldName.equals(p.oldName));
replacement = p.newName;
} else {
replacement = oldName;
}
if (sb.length() > 0) {
sb.append('.');
}
sb.append(replacement);
}
parent.replaceChild(n, Node.newString(sb.toString()));
changed = true;
}
if (changed) {
compiler.reportCodeChange();
}
compiler.setLifeCycleStage(LifeCycleStage.NORMALIZED_OBFUSCATED);
}
/**
* Runs through the list of properties and renames as many as possible with
* names from the previous compilation. Also, updates reservedNames with the
* set of reused names.
* @param reservedNames Reserved names to use during renaming.
* @param allProps Properties to rename.
*/
private void reusePropertyNames(Set<String> reservedNames,
Collection<Property> allProps) {
for (Property prop : allProps) {
// Check if this node can reuse a name from a previous compilation - if
// it can set the newName for the property too.
String prevName = prevUsedPropertyMap.lookupNewName(prop
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
@Override
public boolean isConstructor() {
return referencedType.isConstructor();
}
@Override
public boolean isNominalType() {
return referencedType.isNominalType();
}
@Override
public boolean isInstanceType() {
return referencedType.isInstanceType();
}
@Override
public boolean isInterface() {
return referencedType.isInterface();
}
@Override
public boolean isOrdinaryFunction() {
return referencedType.isOrdinaryFunction();
}
@Override
public TernaryValue testForEquality(JSType that) {
return referencedType.testForEquality(that);
}
@Override
public boolean isSubtype(JSType that) {
return referencedType.isSubtype(that);
}
@Override
public Iterable<ObjectType> getCtorImplementedInterfaces() {
return referencedObjType == null ? Collections.<ObjectType>emptyList() :
referencedObjType.getCtorImplementedInterfaces();
}
@Override
public boolean canAssignTo(JSType that) {
return referencedType.canAssignTo(that);
}
@Override
public boolean isEquivalentTo(JSType that) {
if (this == that) {
return true;
}
return referencedType.isEquivalentTo(that);
}
@Override
public int hashCode() {
return referencedType.hashCode();
}
@Override
public String toString() {
return referencedType.toString();
}
@Override
public ObjectType getImplicitPrototype() {
return referencedObjType == null ? null :
referencedObjType.getImplicitPrototype();
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns, Node propertyNode) {
return referencedObjType == null ? true :
referencedObjType.defineProperty(
propertyName, type, inferred, inExterns, propertyNode);
}
@Override
public boolean isPropertyTypeDeclared(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyTypeDeclared(propertyName);
}
@Override
public Node getPropertyNode(String propertyName) {
return referencedObjType == null ? null :
referencedObjType.getPropertyNode(propertyName);
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyTypeInferred(propertyName);
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> @Override
public boolean isPropertyInExterns(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.isPropertyInExterns(propertyName);
}
@Override
public int getPropertiesCount() {
return referencedObjType == null ? 0 :
referencedObjType.getPropertiesCount();
}
@Override
protected void collectPropertyNames(Set<String> props) {
if (referencedObjType != null) {
referencedObjType.collectPropertyNames(props);
}
}
@Override
public JSType findPropertyType(String propertyName) {
return referencedType.findPropertyType(propertyName);
}
@Override
public JSType getPropertyType(String propertyName) {
return referencedObjType == null ?
getNativeType(JSTypeNative.UNKNOWN_TYPE) :
referencedObjType.getPropertyType(propertyName);
}
@Override
public JSDocInfo getJSDocInfo() {
return referencedType.getJSDocInfo();
}
@Override
public void setJSDocInfo(JSDocInfo info) {
if (referencedObjType != null) {
referencedObjType.setJSDocInfo(info);
}
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return referencedObjType == null ? null :
referencedObjType.getOwnPropertyJSDocInfo(propertyName);
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
if (referencedObjType != null) {
referencedObjType.setPropertyJSDocInfo(propertyName, info, inExterns);
}
}
@Override
public boolean hasProperty(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.hasProperty(propertyName);
}
@Override
public boolean hasOwnProperty(String propertyName) {
return referencedObjType == null ? false :
referencedObjType.hasOwnProperty(propertyName);
}
@Override
public Set<String> getOwnPropertyNames() {
return referencedObjType == null ? ImmutableSet.<String>of() :
referencedObjType.getOwnPropertyNames();
}
@Override
public FunctionType getConstructor() {
return referencedObjType == null ? null :
referencedObjType.getConstructor();
}
@Override
public JSType getParameterType() {
return referencedObjType == null
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
shouldEmitDeprecationWarning(t, n, parent)) {
if (!deprecationInfo.isEmpty()) {
compiler.report(
t.makeError(n, DEPRECATED_CLASS_REASON,
type.toString(), deprecationInfo));
} else {
compiler.report(
t.makeError(n, DEPRECATED_CLASS, type.toString()));
}
}
}
}
/**
* Checks the given NAME node to ensure that access restrictions are obeyed.
*/
private void checkNameDeprecation(NodeTraversal t, Node n, Node parent) {
// Don't bother checking definitions or constructors.
if (parent.getType() == Token.FUNCTION || parent.getType() == Token.VAR ||
parent.getType() == Token.NEW) {
return;
}
Scope.Var var = t.getScope().getVar(n.getString());
JSDocInfo docInfo = var == null ? null : var.getJSDocInfo();
if (docInfo != null && docInfo.isDeprecated() &&
shouldEmitDeprecationWarning(t, n, parent)) {
if (docInfo.getDeprecationReason() != null) {
compiler.report(
t.makeError(n, DEPRECATED_NAME_REASON, n.getString(),
docInfo.getDeprecationReason()));
} else {
compiler.report(
t.makeError(n, DEPRECATED_NAME, n.getString()));
}
}
}
/**
* Checks the given GETPROP node to ensure that access restrictions are
* obeyed.
*/
private void checkPropertyDeprecation(NodeTraversal t, Node n, Node parent) {
// Don't bother checking constructors.
if (parent.getType() == Token.NEW) {
return;
}
ObjectType objectType =
ObjectType.cast(dereference(n.getFirstChild().getJSType()));
String propertyName = n.getLastChild().getString();
if (objectType != null) {
String deprecationInfo
= getPropertyDeprecationInfo(objectType, propertyName);
if (deprecationInfo != null &&
shouldEmitDeprecationWarning(t, n, parent)) {
if (!deprecationInfo.isEmpty()) {
compiler.report(
t.makeError(n, DEPRECATED_PROP_REASON, propertyName,
validator.getReadableJSTypeName(n
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.getFirstChild(), true),
deprecationInfo));
} else {
compiler.report(
t.makeError(n, DEPRECATED_PROP, propertyName,
validator.getReadableJSTypeName(n.getFirstChild(), true)));
}
}
}
}
/**
* Determines whether the given name is visible in the current context.
* @param t The current traversal.
* @param name The name node.
*/
private void checkNameVisibility(NodeTraversal t, Node name, Node parent) {
Var var = t.getScope().getVar(name.getString());
if (var != null) {
JSDocInfo docInfo = var.getJSDocInfo();
if (docInfo != null) {
// If a name is private, make sure that we're in the same file.
Visibility visibility = docInfo.getVisibility();
if (visibility == Visibility.PRIVATE &&
!t.getInput().getName().equals(docInfo.getSourceName())) {
if (docInfo.isConstructor() &&
isValidPrivateConstructorAccess(parent)) {
return;
}
compiler.report(
t.makeError(name, BAD_PRIVATE_GLOBAL_ACCESS,
name.getString(), docInfo.getSourceName()));
}
}
}
}
/**
* Determines whether the given property with @const tag got reassigned
* @param t The current traversal.
* @param getprop The getprop node.
*/
private void checkConstantProperty(NodeTraversal t,
Node getprop) {
// Check whether the property is modified
Node parent = getprop.getParent();
if (!(NodeUtil.isAssignmentOp(parent) && parent.getFirstChild() == getprop)
&& (parent.getType() != Token.INC) && (parent.getType() != Token.DEC)) {
return;
}
ObjectType objectType =
ObjectType.cast(dereference(getprop.getFirstChild().getJSType()));
String propertyName = getprop.getLastChild().getString();
// Check whether constant properties are reassigned
if (objectType != null) {
ObjectType oType = objectType;
while (oType != null) {
if (oType.hasReferenceName()) {
if (initializedConstantProperties.containsEntry(
oType.getReferenceName(), propertyName)) {
compiler.report(
t.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>makeError(getprop, CONST_PROPERTY_REASSIGNED_VALUE,
propertyName));
break;
}
}
oType = oType.getImplicitPrototype();
}
JSDocInfo info = objectType.getOwnPropertyJSDocInfo(propertyName);
if (info != null && info.isConstant()
&& objectType.hasReferenceName()) {
initializedConstantProperties.put(objectType.getReferenceName(),
propertyName);
}
// Add the prototype when we're looking at an instance object
if (objectType.isInstanceType()) {
ObjectType prototype = objectType.getImplicitPrototype();
if (prototype != null) {
JSDocInfo prototypeInfo
= prototype.getOwnPropertyJSDocInfo(propertyName);
if (prototypeInfo != null && prototypeInfo.isConstant()
&& prototype.hasReferenceName()) {
initializedConstantProperties.put(prototype.getReferenceName(),
propertyName);
}
}
}
}
}
/**
* Determines whether the given property is visible in the current context.
* @param t The current traversal.
* @param getprop The getprop node.
*/
private void checkPropertyVisibility(NodeTraversal t,
Node getprop, Node parent) {
ObjectType objectType =
ObjectType.cast(dereference(getprop.getFirstChild().getJSType()));
String propertyName = getprop.getLastChild().getString();
if (objectType != null) {
// Is this a normal property access, or are we trying to override
// an existing property?
boolean isOverride = t.inGlobalScope() &&
parent.getType() == Token.ASSIGN &&
parent.getFirstChild() == getprop;
// Find the lowest property defined on a class with visibility
// information.
if (isOverride) {
objectType = objectType.getImplicitPrototype();
}
JSDocInfo docInfo = null;
for (; objectType != null;
objectType = objectType.getImplicitPrototype()) {
docInfo = objectType.getOwnPropertyJSDocInfo(propertyName);
if (docInfo != null &&
docInfo.getVisibility() != Visibility.INHERITED) {
break;
}
}
if (objectType == null) {
// We couldn't find a visibility modifier; assume it's public.
return;
}
boolean sameInput =
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> t.getInput().getName().equals(docInfo.getSourceName());
Visibility visibility = docInfo.getVisibility();
JSType ownerType = normalizeClassType(objectType);
if (isOverride) {
// Check an ASSIGN statement that's trying to override a property
// on a superclass.
JSDocInfo overridingInfo = parent.getJSDocInfo();
Visibility overridingVisibility = overridingInfo == null ?
Visibility.INHERITED : overridingInfo.getVisibility();
// Check that (a) the property *can* be overridden, and
// (b) that the visibility of the override is the same as the
// visibility of the original property.
if (visibility == Visibility.PRIVATE && !sameInput) {
compiler.report(
t.makeError(getprop, PRIVATE_OVERRIDE,
objectType.toString()));
} else if (overridingVisibility != Visibility.INHERITED &&
overridingVisibility != visibility) {
compiler.report(
t.makeError(getprop, VISIBILITY_MISMATCH,
visibility.name(), objectType.toString(),
overridingVisibility.name()));
}
} else {
if (sameInput) {
// private access is always allowed in the same file.
return;
} else if (visibility == Visibility.PRIVATE &&
(currentClass == null || ownerType.differsFrom(currentClass))) {
if (docInfo.isConstructor() &&
isValidPrivateConstructorAccess(parent)) {
return;
}
// private access is not allowed outside the file from a different
// enclosing class.
compiler.report(
t.makeError(getprop,
BAD_PRIVATE_PROPERTY_ACCESS,
propertyName,
validator.getReadableJSTypeName(
getprop.getFirstChild(), true)));
} else if (visibility == Visibility.PROTECTED) {
// There are 3 types of legal accesses of a protected property:
// 1) Accesses in the same file
// 2) Overriding the property in a subclass
// 3) Accessing the property from inside a subclass
// The first two have already been checked for.
if (currentClass == null || !currentClass.isSubtype(ownerType)) {
compiler.report(
t.makeError(getprop, BAD_PROTECTED_PROPERTY_ACCESS,
propertyName,
validator.getReadable
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
Node scopeRoot = t.getScopeRoot();
Node scopeRootParent = scopeRoot.getParent();
return
// Case #1
(deprecatedDepth > 0) ||
// Case #2
(getTypeDeprecationInfo(t.getScope().getTypeOfThis()) != null) ||
// Case #3
(scopeRootParent != null && scopeRootParent.getType() == Token.ASSIGN &&
getTypeDeprecationInfo(
getClassOfMethod(scopeRoot, scopeRootParent)) != null);
}
/**
* Returns whether this is a function node annotated as deprecated.
*/
private static boolean isDeprecatedFunction(Node n, Node parent) {
if (n.getType() == Token.FUNCTION) {
JSType type = n.getJSType();
if (type != null) {
return getTypeDeprecationInfo(type) != null;
}
}
return false;
}
/**
* Returns the deprecation reason for the type if it is marked
* as being deprecated. Returns empty string if the type is deprecated
* but no reason was given. Returns null if the type is not deprecated.
*/
private static String getTypeDeprecationInfo(JSType type) {
if (type == null) {
return null;
}
JSDocInfo info = type.getJSDocInfo();
if (info != null && info.isDeprecated()) {
if (info.getDeprecationReason() != null) {
return info.getDeprecationReason();
}
return "";
}
ObjectType objType = ObjectType.cast(type);
if (objType != null) {
ObjectType implicitProto = objType.getImplicitPrototype();
if (implicitProto != null) {
return getTypeDeprecationInfo(implicitProto);
}
}
return null;
}
/**
* Returns the deprecation reason for the property if it is marked
* as being deprecated. Returns empty string if the property is deprecated
* but no reason was given. Returns null if the property is not deprecated.
*/
private static String getPropertyDeprecationInfo(ObjectType type,
String prop) {
JSDocInfo info = type.getOwnPropertyJSDocInfo(prop);
if (info != null && info.isDeprecated()) {
if (info.getDeprecationReason() != null) {
return info.getDeprecationReason();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
maybeCutLine();
}
void maybeCutLine() {
}
void endLine() {
}
void notePreferredLineBreak() {
}
void beginBlock() {
if (statementNeedsEnded) {
append(";");
maybeLineBreak();
}
appendBlockStart();
endLine();
statementNeedsEnded = false;
}
void endBlock() {
endBlock(false);
}
void endBlock(boolean shouldEndLine) {
appendBlockEnd();
if (shouldEndLine) {
endLine();
}
statementNeedsEnded = false;
}
void listSeparator() {
add(",");
maybeLineBreak();
}
/**
* Indicates the end of a statement and a ';' may need to be added.
* But we don't add it now, in case we're at the end of a block (in which
* case we don't have to add the ';').
* See maybeEndStatement()
*/
void endStatement() {
endStatement(false);
}
void endStatement(boolean needSemiColon) {
if (needSemiColon) {
append(";");
maybeLineBreak();
statementNeedsEnded = false;
} else if (statementStarted) {
statementNeedsEnded = true;
}
}
/**
* This is to be called when we're in a statement. If the prev statement
* needs to be ended, add a ';'.
*/
void maybeEndStatement() {
// Add a ';' if we need to.
if (statementNeedsEnded) {
append(";");
maybeLineBreak();
endLine();
statementNeedsEnded = false;
}
statementStarted = true;
}
void endFunction() {
endFunction(false);
}
void endFunction(boolean statementContext) {
sawFunction = true;
if (statementContext) {
endLine();
}
}
void beginCaseBody() {
append(":");
}
void endCaseBody() {
}
void add(String newcode) {
maybeEndStatement();
if (newcode.length() == 0) {
return;
}
char c = newcode.charAt(0);
if ((isWordChar(c) || c == '\\') &&
isWordChar(getLastChar())) {
// need space to separate
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>. This is not pretty printing.
// For example: "return foo;"
append(" ");
}
append(newcode);
}
void appendOp(String op, boolean binOp) {
append(op);
}
void addOp(String op, boolean binOp) {
maybeEndStatement();
char first = op.charAt(0);
char prev = getLastChar();
if ((first == '+' || first == '-') && prev == first) {
// This is not pretty printing. This is to prevent misparsing of
// things like "x + ++y" or "x++ + ++y"
append(" ");
} else if (Character.isLetter(first) &&
isWordChar(prev)) {
// Make sure there is a space after e.g. instanceof , typeof
append(" ");
} else if (prev == '-' && first == '>') {
// Make sure that we don't emit -->
append(" ");
}
// Allow formating around the operator.
appendOp(op, binOp);
// Line breaking after an operator is always safe. Line breaking before an
// operator on the other hand is not. We only line break after a bin op
// because it looks strange.
if (binOp) {
maybeCutLine();
}
}
void addNumber(double x) {
// This is not pretty printing. This is to prevent misparsing of x- -4 as
// x--4 (which is a syntax error).
char prev = getLastChar();
if (x < 0 && prev == '-') {
add(" ");
}
if ((long) x == x) {
long value = (long) x;
long mantissa = value;
int exp = 0;
if (Math.abs(x) >= 100) {
while (mantissa / 10 * Math.pow(10, exp + 1) == value) {
mantissa /= 10;
exp++;
}
}
if (exp > 2) {
add(Long.toString(mantissa) + "E" + Integer.toString(exp));
} else {
add(Long.toString(value));
}
} else {
add(String.valueOf(x));
}
}
static boolean is
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.
*
* @return {@code true} if the alternate is in the union
*/
public boolean contains(JSType type) {
for (JSType alt : alternates) {
if (alt.isEquivalentTo(type)) {
return true;
}
}
return false;
}
/**
* Returns a more restricted union type than {@code this} one, in which all
* subtypes of {@code type} have been removed.<p>
*
* Examples:
* <ul>
* <li>{@code (number,string)} restricted by {@code number} is
* {@code string}</li>
* <li>{@code (null, EvalError, URIError)} restricted by
* {@code Error} is {@code null}</li>
* </ul>
*
* @param type the supertype of the types to remove from this union type
*/
public JSType getRestrictedUnion(JSType type) {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
for (JSType t : alternates) {
if (t.isUnknownType() || !t.isSubtype(type)) {
restricted.addAlternate(t);
}
}
return restricted.build();
}
@Override public String toString() {
StringBuilder result = new StringBuilder();
boolean firstAlternate = true;
result.append("(");
SortedSet<JSType> sorted = new TreeSet<JSType>(ALPHA);
sorted.addAll(alternates);
for (JSType t : sorted) {
if (!firstAlternate) {
result.append("|");
}
result.append(t.toString());
firstAlternate = false;
}
result.append(")");
return result.toString();
}
@Override
public boolean isSubtype(JSType that) {
// unknown
if (that.isUnknownType()) {
return true;
}
// all type
if (that.isAllType()) {
return true;
}
for (JSType element : alternates) {
if (!element.isSubtype(that)) {
return false;
}
}
return true;
}
@Override
public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
// gather elements after restriction
UnionTypeBuilder restricted = new UnionTypeBuilder(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.
return getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public boolean hasProperty(String propertyName) {
// has all properties, since it is any object
return true;
}
@Override
boolean defineProperty(String propertyName, JSType type,
boolean inferred, boolean inExterns, Node propertyNode) {
// nothing, all properties are defined
return true;
}
@Override
public JSDocInfo getOwnPropertyJSDocInfo(String propertyName) {
return null;
}
@Override
public void setPropertyJSDocInfo(String propertyName, JSDocInfo info,
boolean inExterns) {
// Do nothing, specific properties do not have JSDocInfo.
}
@Override
public boolean isPropertyTypeInferred(String propertyName) {
return false;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNoObjectType();
}
@Override
public String toString() {
return "NoObject";
}
@Override
public FunctionType getConstructor() {
return null;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
*/
public class ScriptRuntime {
/**
* No instances should be created.
*/
protected ScriptRuntime() {
}
// It is public so NativeRegExp can access it .
public static boolean isJSLineTerminator(int c)
{
// Optimization for faster check for eol character:
// they do not have 0xDFD0 bits set
if ((c & 0xDFD0) != 0) {
return false;
}
return c == '\n' || c == '\r' || c == 0x2028 || c == 0x2029;
}
// Can not use Double.NaN defined as 0.0d / 0.0 as under the Microsoft VM,
// versions 2.01 and 3.0P1, that causes some uses (returns at least) of
// Double.NaN to be converted to 1.0.
// So we use ScriptRuntime.NaN instead of Double.NaN.
public static final double
NaN = Double.longBitsToDouble(0x7ff8000000000000L);
// A similar problem exists for negative zero.
public static final double
negativeZero = Double.longBitsToDouble(0x8000000000000000L);
public static final Double NaNobj = new Double(NaN);
/*
* Helper function for toNumber, parseInt, and TokenStream.getToken.
*/
@SuppressWarnings("fallthrough")
static double stringToNumber(String s, int start, int radix) {
char digitMax = '9';
char lowerCaseBound = 'a';
char upperCaseBound = 'A';
int len = s.length();
if (radix < 10) {
digitMax = (char) ('0' + radix - 1);
}
if (radix > 10) {
lowerCaseBound = (char) ('a' + radix - 10);
upperCaseBound = (char) ('A' + radix - 10);
}
int end;
double sum = 0.0;
for (end=start; end < len; end++) {
char c = s.charAt(end);
int newDigit;
if
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> ('0' <= c && c <= digitMax)
newDigit = c - '0';
else if ('a' <= c && c < lowerCaseBound)
newDigit = c - 'a' + 10;
else if ('A' <= c && c < upperCaseBound)
newDigit = c - 'A' + 10;
else
break;
sum = sum*radix + newDigit;
}
if (start == end) {
return NaN;
}
if (sum >= 9007199254740992.0) {
if (radix == 10) {
/* If we're accumulating a decimal number and the number
* is >= 2^53, then the result from the repeated multiply-add
* above may be inaccurate. Call Java to get the correct
* answer.
*/
try {
return Double.valueOf(s.substring(start, end)).doubleValue();
} catch (NumberFormatException nfe) {
return NaN;
}
} else if (radix == 2 || radix == 4 || radix == 8 ||
radix == 16 || radix == 32)
{
/* The number may also be inaccurate for one of these bases.
* This happens if the addition in value*radix + digit causes
* a round-down to an even least significant mantissa bit
* when the first dropped bit is a one. If any of the
* following digits in the number (which haven't been added
* in yet) are nonzero then the correct action would have
* been to round up instead of down. An example of this
* occurs when reading the number 0x1000000000000081, which
* rounds to 0x1000000000000000 instead of 0x1000000000000100.
*/
int bitShiftInChar = 1;
int digit = 0;
final int SKIP_LEADING_ZEROS = 0;
final int FIRST_EXACT_53_BITS = 1;
final int AFTER_BIT_53 = 2;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
final int ZEROS_AFTER_54 = 3;
final int MIXED_AFTER_54 = 4;
int state = SKIP_LEADING_ZEROS;
int exactBitsLimit = 53;
double factor = 0.0;
boolean bit53 = false;
// bit54 is the 54th bit (the first dropped from the mantissa)
boolean bit54 = false;
for (;;) {
if (bitShiftInChar == 1) {
if (start == end)
break;
digit = s.charAt(start++);
if ('0' <= digit && digit <= '9')
digit -= '0';
else if ('a' <= digit && digit <= 'z')
digit -= 'a' - 10;
else
digit -= 'A' - 10;
bitShiftInChar = radix;
}
bitShiftInChar >>= 1;
boolean bit = (digit & bitShiftInChar) != 0;
switch (state) {
case SKIP_LEADING_ZEROS:
if (bit) {
--exactBitsLimit;
sum = 1.0;
state = FIRST_EXACT_53_BITS;
}
break;
case FIRST_EXACT_53_BITS:
sum *= 2.0;
if (bit)
sum += 1.0;
--exactBitsLimit;
if (exactBitsLimit == 0) {
bit53 = bit;
state = AFTER_BIT_53;
}
break;
case AFTER_BIT_53:
bit54 = bit;
factor = 2.0;
state = ZEROS_AFTER_54;
break;
case ZEROS_AFTER_54:
if (bit) {
state = MIXED_AFTER_54;
}
// fallthrough
case MIXED_AFTER_54:
factor *= 2;
break;
}
}
switch (state) {
case SKIP_LEADING_ZEROS:
sum = 0.0;
break;
case FIRST_EXACT_53_BITS:
case AFTER_BIT_53:
// do nothing
break;
case ZER
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>OS_AFTER_54:
// x1.1 -> x1 + 1 (round up)
// x0.1 -> x0 (round down)
if (bit54 & bit53)
sum += 1.0;
sum *= factor;
break;
case MIXED_AFTER_54:
// x.100...1.. -> x + 1 (round up)
// x.0anything -> x (round down)
if (bit54)
sum += 1.0;
sum *= factor;
break;
}
}
/* We don't worry about inaccurate numbers for any other base. */
}
return sum;
}
public static String escapeString(String s)
{
return escapeString(s, '"');
}
/**
* For escaping strings printed by object and array literals; not quite
* the same as 'escape.'
*/
public static String escapeString(String s, char escapeQuote)
{
if (!(escapeQuote == '"' || escapeQuote == '\'')) Kit.codeBug();
StringBuffer sb = null;
for(int i = 0, L = s.length(); i != L; ++i) {
int c = s.charAt(i);
if (' ' <= c && c <= '~' && c != escapeQuote && c != '\\') {
// an ordinary print character (like C isprint()) and not "
// or \ .
if (sb != null) {
sb.append((char)c);
}
continue;
}
if (sb == null) {
sb = new StringBuffer(L + 3);
sb.append(s);
sb.setLength(i);
}
int escape = -1;
switch (c) {
case '\b': escape = 'b'; break;
case '\f': escape = 'f'; break;
case '\n': escape = 'n'; break;
case '\r': escape = 'r'; break;
case '\t': escape = 't'; break;
case 0xb: escape = 'v'; break; // Java lacks \v.
case ' ': escape = ' '; break;
case '\\': escape = '\\'; break
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>;
}
if (escape >= 0) {
// an \escaped sort of character
sb.append('\\');
sb.append((char)escape);
} else if (c == escapeQuote) {
sb.append('\\');
sb.append(escapeQuote);
} else {
int hexSize;
if (c < 256) {
// 2-digit hex
sb.append("\\x");
hexSize = 2;
} else {
// Unicode.
sb.append("\\u");
hexSize = 4;
}
// append hexadecimal form of c left-padded with 0
for (int shift = (hexSize - 1) * 4; shift >= 0; shift -= 4) {
int digit = 0xf & (c >> shift);
int hc = (digit < 10) ? '0' + digit : 'a' - 10 + digit;
sb.append((char)hc);
}
}
}
return (sb == null) ? s : sb.toString();
}
static boolean isValidIdentifierName(String s)
{
int L = s.length();
if (L == 0)
return false;
if (!Character.isJavaIdentifierStart(s.charAt(0)))
return false;
for (int i = 1; i != L; ++i) {
if (!Character.isJavaIdentifierPart(s.charAt(i)))
return false;
}
return !TokenStream.isKeyword(s);
}
/**
* Convert the value to a string.
*
* See ECMA 9.8.
*/
public static String toString(Object val) {
for (;;) {
if (val == null) {
return "null";
}
if (val instanceof String) {
return (String)val;
}
if (val instanceof Number) {
// XXX should we just teach NativeNumber.stringValue()
// about Numbers?
return numberToString(((Number)val).doubleValue(), 10);
}
return val.toString();
}
}
public static String numberToString(double d, int base) {
if (d != d)
return "NaN";
if (d == Double.POSITIVE_INFINITY)
return "Infinity";
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> if (d == Double.NEGATIVE_INFINITY)
return "-Infinity";
if (d == 0.0)
return "0";
if ((base < 2) || (base > 36)) {
throw Context.reportRuntimeError1(
"msg.bad.radix", Integer.toString(base));
}
if (base != 10) {
return DToA.JS_dtobasestr(base, d);
} else {
StringBuffer result = new StringBuffer();
DToA.JS_dtostr(result, DToA.DTOSTR_STANDARD, 0, d);
return result.toString();
}
}
/**
* If str is a decimal presentation of Uint32 value, return it as long.
* Othewise return -1L;
*/
public static long testUint32String(String str)
{
// The length of the decimal string representation of
// UINT32_MAX_VALUE, 4294967296
final int MAX_VALUE_LENGTH = 10;
int len = str.length();
if (1 <= len && len <= MAX_VALUE_LENGTH) {
int c = str.charAt(0);
c -= '0';
if (c == 0) {
// Note that 00,01 etc. are not valid Uint32 presentations
return (len == 1) ? 0L : -1L;
}
if (1 <= c && c <= 9) {
long v = c;
for (int i = 1; i != len; ++i) {
c = str.charAt(i) - '0';
if (!(0 <= c && c <= 9)) {
return -1;
}
v = 10 * v + c;
}
// Check for overflow
if ((v >>> 32) == 0) {
return v;
}
}
}
return -1;
}
static boolean isSpecialProperty(String s)
{
return s.equals("__proto__") || s.equals("__parent__");
}
// ------------------
// Statements
// ------------------
public static String getMessage0(String messageId)
{
return getMessage(messageId, null);
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>p[0], null, 0);
}
public static EcmaError constructError(String error,
String message,
String sourceName,
int lineNumber,
String lineSource,
int columnNumber)
{
return new EcmaError(error, message, sourceName,
lineNumber, lineSource, columnNumber);
}
public static EcmaError typeError(String message)
{
return constructError("TypeError", message);
}
public static EcmaError typeError0(String messageId)
{
String msg = getMessage0(messageId);
return typeError(msg);
}
public static EcmaError typeError1(String messageId, String arg1)
{
String msg = getMessage1(messageId, arg1);
return typeError(msg);
}
public static EcmaError typeError2(String messageId, String arg1,
String arg2)
{
String msg = getMessage2(messageId, arg1, arg2);
return typeError(msg);
}
public static EcmaError typeError3(String messageId, String arg1,
String arg2, String arg3)
{
String msg = getMessage3(messageId, arg1, arg2, arg3);
return typeError(msg);
}
public static RuntimeException undefReadError(Object object, Object id)
{
String idStr = (id == null) ? "null" : id.toString();
return typeError2("msg.undef.prop.read", toString(object), idStr);
}
public static RuntimeException undefCallError(Object object, Object id)
{
String idStr = (id == null) ? "null" : id.toString();
return typeError2("msg.undef.method.call", toString(object), idStr);
}
public static RuntimeException undefWriteError(Object object,
Object id,
Object value)
{
String idStr = (id == null) ? "null" : id.toString();
String valueStr = toString(value);
return typeError3("msg.undef.prop.write", toString(object), idStr,
valueStr);
}
public static RuntimeException notFunctionError(Object value)
{
return notFunctionError(value, value);
}
public static RuntimeException notFunctionError(Object value,
Object message
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Helper)
{
// XXX Use value for better error reporting
String msg = (messageHelper == null)
? "null" : messageHelper.toString();
return typeError2("msg.isnt.function", msg,
value == null ? "null" : value.getClass().getName());
}
static int lastIndexResult(Context cx)
{
return cx.scratchIndex;
}
public static void storeUint32Result(Context cx, long value)
{
if ((value >>> 32) != 0)
throw new IllegalArgumentException();
cx.scratchUint32 = value;
}
public static long lastUint32Result(Context cx)
{
long value = cx.scratchUint32;
if ((value >>> 32) != 0)
throw new IllegalStateException();
return value;
}
static String makeUrlForGeneratedScript
(boolean isEval, String masterScriptUrl, int masterScriptLine)
{
if (isEval) {
return masterScriptUrl+'#'+masterScriptLine+"(eval)";
} else {
return masterScriptUrl+'#'+masterScriptLine+"(Function)";
}
}
static boolean isGeneratedScript(String sourceUrl) {
// ALERT: this may clash with a valid URL containing (eval) or
// (Function)
return sourceUrl.indexOf("(eval)") >= 0
|| sourceUrl.indexOf("(Function)") >= 0;
}
public static final Object[] emptyArgs = new Object[0];
public static final String[] emptyStrings = new String[0];
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
// memory footprint associated with these (similar to IRFactory).
private final Node templateNode;
private class ErrorReporterParser {
void addParserWarning(String messageId, String messageArg, int lineno,
int charno) {
errorReporter.warning(ScriptRuntime.getMessage1(messageId, messageArg),
sourceName, lineno, null, charno);
}
void addParserWarning(String messageId, int lineno, int charno) {
errorReporter.warning(ScriptRuntime.getMessage0(messageId),
sourceName, lineno, null, charno);
}
void addTypeWarning(String messageId, String messageArg, int lineno,
int charno) {
errorReporter.warning(
"Bad type annotation. " +
ScriptRuntime.getMessage1(messageId, messageArg),
sourceName, lineno, null, charno);
}
void addTypeWarning(String messageId, int lineno, int charno) {
errorReporter.warning(
"Bad type annotation. " +
ScriptRuntime.getMessage0(messageId),
sourceName, lineno, null, charno);
}
}
// The DocInfo with the fileoverview tag for the whole file.
private JSDocInfo fileOverviewJSDocInfo = null;
private State state;
private final Map<String, Annotation> annotationNames;
private final Set<String> suppressionNames;
static private final Set<String> modifiesAnnotationKeywords =
ImmutableSet.<String>of("this", "arguments");
private Node.FileLevelJsDocBuilder fileLevelJsDocBuilder;
/**
* Sets the JsDocBuilder for the file-level (root) node of this parse. The
* parser uses the builder to append any preserve annotations it encounters
* in jsdoc comments.
*
* @param fileLevelJsDocBuilder
*/
void setFileLevelJsDocBuilder(
Node.FileLevelJsDocBuilder fileLevelJsDocBuilder) {
this.fileLevelJsDocBuilder = fileLevelJsDocBuilder;
}
/**
* Sets the file overview JSDocInfo, in order to warn about multiple uses of
* the @fileoverview tag in a file.
*/
void setFileOverviewJSDocInfo(JSDocInfo fileOverviewJSDocInfo) {
this.fileOverviewJSDocInfo = fileOverview
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
token = blockInfo.token;
if (!blockInfo.string.isEmpty()) {
jsdocBuilder.recordBlockDescription(blockInfo.string);
}
} else {
if (token != JsDocToken.ANNOTATION &&
token != JsDocToken.EOC) {
// Mark that there was a description, but don't bother marking
// what it was.
jsdocBuilder.recordBlockDescription("");
}
}
// Parse the actual JsDoc.
retry: for (;;) {
switch (token) {
case ANNOTATION:
if (state == State.SEARCHING_ANNOTATION) {
state = State.SEARCHING_NEWLINE;
lineno = stream.getLineno();
charno = stream.getCharno();
String annotationName = stream.getString();
Annotation annotation = annotationNames.get(annotationName);
if (annotation == null) {
parser.addParserWarning("msg.bad.jsdoc.tag", annotationName,
stream.getLineno(), stream.getCharno());
} else {
// Mark the beginning of the annotation.
jsdocBuilder.markAnnotation(annotationName, lineno, charno);
switch (annotation) {
case AUTHOR:
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo authorInfo = extractSingleLineBlock();
String author = authorInfo.string;
if (author.length() == 0) {
parser.addParserWarning("msg.jsdoc.authormissing",
stream.getLineno(), stream.getCharno());
} else {
jsdocBuilder.addAuthor(author);
}
token = authorInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case CONSTANT:
if (!jsdocBuilder.recordConstancy()) {
parser.addParserWarning("msg.jsdoc.const",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case CONSTRUCTOR:
if (!jsdocBuilder.recordConstructor()) {
if (jsdocBuilder.isInterfaceRecorded()) {
parser.addTypeWarning("msg.jsdoc.interface.constructor",
stream.getLineno(), stream.getCharno());
} else {
parser.add
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>TypeWarning("msg.jsdoc.incompat.type",
stream.getLineno(), stream.getCharno());
}
}
token = eatTokensUntilEOL();
continue retry;
case DEPRECATED:
if (!jsdocBuilder.recordDeprecated()) {
parser.addParserWarning("msg.jsdoc.deprecated",
stream.getLineno(), stream.getCharno());
}
// Find the reason/description, if any.
ExtractionInfo reasonInfo =
extractMultilineTextualBlock(token);
String reason = reasonInfo.string;
if (reason.length() > 0) {
jsdocBuilder.recordDeprecationReason(reason);
}
token = reasonInfo.token;
continue retry;
case INTERFACE:
if (!jsdocBuilder.recordInterface()) {
if (jsdocBuilder.isConstructorRecorded()) {
parser.addTypeWarning("msg.jsdoc.interface.constructor",
stream.getLineno(), stream.getCharno());
} else {
parser.addTypeWarning("msg.jsdoc.incompat.type",
stream.getLineno(), stream.getCharno());
}
}
token = eatTokensUntilEOL();
continue retry;
case DESC:
if (jsdocBuilder.isDescriptionRecorded()) {
parser.addParserWarning("msg.jsdoc.desc.extra",
stream.getLineno(), stream.getCharno());
token = eatTokensUntilEOL();
continue retry;
} else {
ExtractionInfo descriptionInfo =
extractMultilineTextualBlock(token);
String description = descriptionInfo.string;
jsdocBuilder.recordDescription(description);
token = descriptionInfo.token;
continue retry;
}
case FILE_OVERVIEW:
String fileOverview = "";
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo fileOverviewInfo =
extractMultilineTextualBlock(token,
WhitespaceOption.TRIM);
fileOverview = fileOverviewInfo.string;
token = fileOverviewInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
if (!jsdocBuilder.recordFileOverview(fileOverview) ||
fileOverviewJSDocInfo != null) {
parser.addParserWarning("msg.jsdoc.fileoverview.extra
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>",
stream.getLineno(), stream.getCharno());
}
continue retry;
case LICENSE:
case PRESERVE:
ExtractionInfo preserveInfo =
extractMultilineTextualBlock(token,
WhitespaceOption.PRESERVE);
String preserve = preserveInfo.string;
if (preserve.length() > 0) {
if (fileLevelJsDocBuilder != null) {
fileLevelJsDocBuilder.append(preserve);
}
}
token = preserveInfo.token;
continue retry;
case ENUM:
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
type = null;
if (token != JsDocToken.EOL && token != JsDocToken.EOC) {
type = createJSTypeExpression(
parseAndRecordTypeNode(token));
}
if (type == null) {
type = createJSTypeExpression(newStringNode("number"));
}
if (!jsdocBuilder.recordEnumParameterType(type)) {
parser.addTypeWarning(
"msg.jsdoc.incompat.type", lineno, charno);
}
token = eatTokensUntilEOL(token);
continue retry;
case EXPORT:
if (!jsdocBuilder.recordExport()) {
parser.addParserWarning("msg.jsdoc.export",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case EXTERNS:
if (!jsdocBuilder.recordExterns()) {
parser.addParserWarning("msg.jsdoc.externs",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case JAVA_DISPATCH:
if (!jsdocBuilder.recordJavaDispatch()) {
parser.addParserWarning("msg.jsdoc.javadispatch",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case EXTENDS:
case IMPLEMENTS:
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
boolean matchingRc = false;
if (token == JsDocToken.LC) {
token
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> = next();
lineno = stream.getLineno();
charno = stream.getCharno();
type = null;
if (token == JsDocToken.LC) {
type = createJSTypeExpression(
parseAndRecordTypeNode(token));
if (type == null) {
// parsing error reported during recursive descent
// recovering parsing
token = eatTokensUntilEOL();
continue retry;
}
}
// *Update* the token to that after the type annotation.
token = current();
// Save the throw type.
jsdocBuilder.recordThrowType(type);
// Find the throw's description (if applicable).
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo descriptionInfo =
extractMultilineTextualBlock(token);
String description = descriptionInfo.string;
if (description.length() > 0) {
jsdocBuilder.recordThrowDescription(type, description);
}
token = descriptionInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case PARAM:
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
type = null;
if (token == JsDocToken.LC) {
type = createJSTypeExpression(
parseAndRecordParamTypeNode(token));
if (type == null) {
// parsing error reported during recursive descent
// recovering parsing
token = eatTokensUntilEOL();
continue retry;
}
skipEOLs();
token = next();
lineno = stream.getLineno();
charno = stream.getCharno();
}
String name = null;
boolean isBracketedParam = JsDocToken.LB == token;
if (isBracketedParam) {
token = next();
}
if (JsDocToken.STRING != token) {
parser.addTypeWarning("msg.missing.variable.name",
lineno, charno);
} else {
name = stream.getString();
if (isBracketedParam) {
token = next();
// Throw out JsDocToolkit's "default" parameter
// annotation. It makes no sense under our type
// system.
if (JsDocToken.EQUALS == token) {
token =
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> next();
if (JsDocToken.STRING == token) {
token = next();
}
}
if (JsDocToken.RB != token) {
reportTypeSyntaxWarning("msg.jsdoc.missing.rb");
} else if (type != null) {
// Make the type expression optional, if it isn't
// already.
type = JSTypeExpression.makeOptionalArg(type);
}
}
// If the param name has a DOT in it, just throw it out
// quietly. We do not handle the JsDocToolkit method
// for handling properties of params.
if (name.indexOf('.') > -1) {
name = null;
} else if (!jsdocBuilder.recordParameter(name, type)) {
if (jsdocBuilder.hasParameter(name)) {
parser.addTypeWarning("msg.dup.variable.name", name,
lineno, charno);
} else {
parser.addTypeWarning("msg.jsdoc.incompat.type", name,
lineno, charno);
}
}
}
if (name == null) {
token = eatTokensUntilEOL(token);
continue retry;
}
jsdocBuilder.markName(name, lineno, charno);
// Find the parameter's description (if applicable).
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo paramDescriptionInfo =
extractMultilineTextualBlock(token);
String paramDescription = paramDescriptionInfo.string;
if (paramDescription.length() > 0) {
jsdocBuilder.recordParameterDescription(name,
paramDescription);
}
token = paramDescriptionInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case PRESERVE_TRY:
if (!jsdocBuilder.recordPreserveTry()) {
parser.addParserWarning("msg.jsdoc.preservertry",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case PRIVATE:
if (!jsdocBuilder.recordVisibility(Visibility.PRIVATE)) {
parser.addParserWarning("msg.jsdoc.visibility.private",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> retry;
case PROTECTED:
if (!jsdocBuilder.recordVisibility(Visibility.PROTECTED)) {
parser.addParserWarning("msg.jsdoc.visibility.protected",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case PUBLIC:
if (!jsdocBuilder.recordVisibility(Visibility.PUBLIC)) {
parser.addParserWarning("msg.jsdoc.visibility.public",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case NO_SHADOW:
if (!jsdocBuilder.recordNoShadow()) {
parser.addParserWarning("msg.jsdoc.noshadow",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case NO_SIDE_EFFECTS:
if (!jsdocBuilder.recordNoSideEffects()) {
parser.addParserWarning("msg.jsdoc.nosideeffects",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case MODIFIES:
token = parseModifiesTag(next());
continue retry;
case IMPLICIT_CAST:
if (!jsdocBuilder.recordImplicitCast()) {
parser.addTypeWarning("msg.jsdoc.implicitcast",
stream.getLineno(), stream.getCharno());
}
token = eatTokensUntilEOL();
continue retry;
case SEE:
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo referenceInfo = extractSingleLineBlock();
String reference = referenceInfo.string;
if (reference.length() == 0) {
parser.addParserWarning("msg.jsdoc.seemissing",
stream.getLineno(), stream.getCharno());
} else {
jsdocBuilder.addReference(reference);
}
token = referenceInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case SUPPRESS:
token = parseSuppressTag(next());
continue retry;
case TEMPLATE:
ExtractionInfo templateInfo = extractSingleLineBlock();
String templateTypeName = templateInfo.string;
if (template
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>TypeName.length() == 0) {
parser.addTypeWarning("msg.jsdoc.templatemissing",
stream.getLineno(), stream.getCharno());
} else if (!jsdocBuilder.recordTemplateTypeName(
templateTypeName)) {
parser.addTypeWarning("msg.jsdoc.template.at.most.once",
stream.getLineno(), stream.getCharno());
}
token = templateInfo.token;
continue retry;
case VERSION:
ExtractionInfo versionInfo = extractSingleLineBlock();
String version = versionInfo.string;
if (version.length() == 0) {
parser.addParserWarning("msg.jsdoc.versionmissing",
stream.getLineno(), stream.getCharno());
} else {
if (!jsdocBuilder.recordVersion(version)) {
parser.addParserWarning("msg.jsdoc.extraversion",
stream.getLineno(), stream.getCharno());
}
}
token = versionInfo.token;
continue retry;
case DEFINE:
case RETURN:
case THIS:
case TYPE:
case TYPEDEF:
lineno = stream.getLineno();
charno = stream.getCharno();
Node typeNode = null;
if (!lookAheadForTypeAnnotation() &&
annotation == Annotation.RETURN) {
// If RETURN doesn't have a type annotation, record
// it as the unknown type.
typeNode = newNode(Token.QMARK);
} else {
skipEOLs();
token = next();
typeNode = parseAndRecordTypeNode(token, lineno, charno);
}
if (annotation == Annotation.THIS) {
typeNode = wrapNode(Token.BANG, typeNode);
if (typeNode != null && token != JsDocToken.LC) {
typeNode.putBooleanProp(Node.BRACELESS_TYPE, true);
}
}
type = createJSTypeExpression(typeNode);
if (type == null) {
// error reported during recursive descent
// recovering parsing
} else {
switch (annotation) {
case DEFINE:
if (!jsdocBuilder.recordDefineType(type)) {
parser.addParserWarning("msg.jsdoc.define",
lineno, charno);
}
break;
case RETURN:
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
if (!jsdocBuilder.recordReturnType(type)) {
parser.addTypeWarning(
"msg.jsdoc.incompat.type", lineno, charno);
break;
}
// Find the return's description (if applicable).
if (jsdocBuilder.shouldParseDocumentation()) {
ExtractionInfo returnDescriptionInfo =
extractMultilineTextualBlock(token);
String returnDescription =
returnDescriptionInfo.string;
if (returnDescription.length() > 0) {
jsdocBuilder.recordReturnDescription(
returnDescription);
}
token = returnDescriptionInfo.token;
} else {
token = eatTokensUntilEOL(token);
}
continue retry;
case THIS:
if (!jsdocBuilder.recordThisType(type)) {
parser.addTypeWarning(
"msg.jsdoc.incompat.type", lineno, charno);
}
break;
case TYPE:
if (!jsdocBuilder.recordType(type)) {
parser.addTypeWarning(
"msg.jsdoc.incompat.type", lineno, charno);
}
break;
case TYPEDEF:
if (!jsdocBuilder.recordTypedef(type)) {
parser.addTypeWarning(
"msg.jsdoc.incompat.type", lineno, charno);
}
break;
}
token = eatTokensUntilEOL();
}
continue retry;
}
}
}
break;
case EOC:
if (hasParsedFileOverviewDocInfo()) {
fileOverviewJSDocInfo = retrieveAndResetParsedJSDocInfo();
}
return true;
case EOF:
// discard any accumulated information
jsdocBuilder.build(null);
parser.addParserWarning("msg.unexpected.eof",
stream.getLineno(), stream.getCharno());
return false;
case EOL:
if (state == State.SEARCHING_NEWLINE) {
state = State.SEARCHING_ANNOTATION;
}
token = next();
continue retry;
default:
if (token == JsDocToken.STAR && state == State.SEARCHING_ANNOTATION) {
token = next();
continue retry;
} else {
state = State.SEARCHING_NEWLINE;
token = eatTokensUntilEOL();
continue retry
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> Whether the type expression starts with a "{".
* @param onlyParseSimpleNames If true, only simple type names are parsed
* (via a call to parseTypeNameAnnotation instead of
* parseTypeExpressionAnnotation).
* @return The type expression found or null if none.
*/
private Node parseAndRecordTypeNode(JsDocToken token, int lineno,
int startCharno,
boolean matchingLC,
boolean onlyParseSimpleNames) {
Node typeNode = null;
if (onlyParseSimpleNames) {
typeNode = parseTypeNameAnnotation(token);
} else {
typeNode = parseTypeExpressionAnnotation(token);
}
if (typeNode != null && !matchingLC) {
typeNode.putBooleanProp(Node.BRACELESS_TYPE, true);
}
int endCharno = stream.getCharno();
jsdocBuilder.markTypeNode(typeNode, lineno, startCharno, endCharno,
matchingLC);
return typeNode;
}
/**
* Converts a JSDoc token to its string representation.
*/
private String toString(JsDocToken token) {
switch (token) {
case ANNOTATION:
return "@" + stream.getString();
case BANG:
return "!";
case COMMA:
return ",";
case COLON:
return ":";
case GT:
return ">";
case LB:
return "[";
case LC:
return "{";
case LP:
return "(";
case LT:
return ".<";
case QMARK:
return "?";
case PIPE:
return "|";
case RB:
return "]";
case RC:
return "}";
case RP:
return ")";
case STAR:
return "*";
case ELLIPSIS:
return "...";
case EQUALS:
return "=";
case STRING:
return stream.getString();
default:
throw new IllegalStateException(token.toString());
}
}
/**
* Constructs a new {@code JSTypeExpression}.
* @param n A node. May be null.
*/
private JSTypeExpression createJSTypeExpression(Node n) {
return n == null ? null :
new JSTypeExpression(n, sourceName);
}
/**
* Tuple for returning both the string extracted and the
* new token
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> following a call to any of the extract*Block
* methods.
*/
private static class ExtractionInfo {
private final String string;
private final JsDocToken token;
public ExtractionInfo(String string, JsDocToken token) {
this.string = string;
this.token = token;
}
}
/**
* Extracts the text found on the current line starting at token. Note that
* token = token.info; should be called after this method is used to update
* the token properly in the parser.
*
* @return The extraction information.
*/
private ExtractionInfo extractSingleLineBlock() {
// Get the current starting point.
stream.update();
int lineno = stream.getLineno();
int charno = stream.getCharno() + 1;
String line = stream.getRemainingJSDocLine().trim();
// Record the textual description.
if (line.length() > 0) {
jsdocBuilder.markText(line, lineno, charno, lineno,
charno + line.length());
}
return new ExtractionInfo(line, next());
}
private ExtractionInfo extractMultilineTextualBlock(JsDocToken token) {
return extractMultilineTextualBlock(token, WhitespaceOption.SINGLE_LINE);
}
private enum WhitespaceOption {
/**
* Preserves all whitespace and formatting. Needed for licenses and
* purposely formatted text.
*/
PRESERVE,
/** Preserves newlines but trims the output. */
TRIM,
/** Removes newlines and turns the output into a single line string. */
SINGLE_LINE
}
/**
* Extracts the text found on the current line and all subsequent
* until either an annotation, end of comment or end of file is reached.
* Note that if this method detects an end of line as the first token, it
* will quit immediately (indicating that there is no text where it was
* expected). Note that token = info.token; should be called after this
* method is used to update the token properly in the parser.
*
* @param token The start token.
* @param option How to handle whitespace.
*
* @return The extraction information.
*/
@SuppressWarnings("fallthrough")
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
private ExtractionInfo extractMultilineTextualBlock(JsDocToken token,
WhitespaceOption option) {
if (token == JsDocToken.EOC || token == JsDocToken.EOL ||
token == JsDocToken.EOF) {
return new ExtractionInfo("", token);
}
stream.update();
int startLineno = stream.getLineno();
int startCharno = stream.getCharno() + 1;
// Read the content from the first line.
String line = stream.getRemainingJSDocLine();
if (option != WhitespaceOption.PRESERVE) {
line = line.trim();
}
StringBuilder builder = new StringBuilder();
builder.append(line);
state = State.SEARCHING_ANNOTATION;
token = next();
boolean ignoreStar = false;
do {
switch (token) {
case STAR:
if (!ignoreStar) {
if (builder.length() > 0) {
builder.append(' ');
}
builder.append('*');
}
token = next();
continue;
case EOL:
if (option != WhitespaceOption.SINGLE_LINE) {
builder.append("\n");
}
ignoreStar = true;
token = next();
continue;
case ANNOTATION:
case EOC:
case EOF:
// When we're capturing a license block, annotations
// in the block are ok.
if (!(option == WhitespaceOption.PRESERVE &&
token == JsDocToken.ANNOTATION)) {
String multilineText = builder.toString();
if (option != WhitespaceOption.PRESERVE) {
multilineText = multilineText.trim();
}
int endLineno = stream.getLineno();
int endCharno = stream.getCharno();
if (multilineText.length() > 0) {
jsdocBuilder.markText(multilineText, startLineno, startCharno,
endLineno, endCharno);
}
return new ExtractionInfo(multilineText, token);
}
// FALL THROUGH
default:
ignoreStar = false;
state = State.SEARCHING_ANNOTATION;
if (builder.length() > 0) {
builder.append(' ');
}
builder.append
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(toString(token));
line = stream.getRemainingJSDocLine();
if (option != WhitespaceOption.PRESERVE) {
line = trimEnd(line);
}
builder.append(line);
token = next();
}
} while (true);
}
/**
* Extracts the top-level block comment from the JsDoc comment, if any.
* This method differs from the extractMultilineTextualBlock in that it
* terminates under different conditions (it doesn't have the same
* prechecks), it does not first read in the remaining of the current
* line and its conditions for ignoring the "*" (STAR) are different.
*
* @param token The starting token.
*
* @return The extraction information.
*/
private ExtractionInfo extractBlockComment(JsDocToken token) {
StringBuilder builder = new StringBuilder();
boolean ignoreStar = true;
do {
switch (token) {
case ANNOTATION:
case EOC:
case EOF:
return new ExtractionInfo(builder.toString().trim(), token);
case STAR:
if (!ignoreStar) {
if (builder.length() > 0) {
builder.append(' ');
}
builder.append('*');
}
token = next();
continue;
case EOL:
ignoreStar = true;
builder.append('\n');
token = next();
continue;
default:
if (!ignoreStar && builder.length() > 0) {
builder.append(' ');
}
ignoreStar = false;
builder.append(toString(token));
String line = stream.getRemainingJSDocLine();
line = trimEnd(line);
builder.append(line);
token = next();
}
} while (true);
}
/**
* Trim characters from only the end of a string.
* This method will remove all whitespace characters
* (defined by Character.isWhitespace(char), in addition to the characters
* provided, from the end of the provided string.
*
* @param s String to be trimmed
* @return String with whitespace and characters in extraChars removed
* from the end.
*/
private static String trimEnd(String s) {
int trimCount = 0;
while (trimCount < s.length())
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
char ch = s.charAt(s.length() - trimCount - 1);
if (Character.isWhitespace(ch)) {
trimCount++;
} else {
break;
}
}
if (trimCount == 0) {
return s;
}
return s.substring(0, s.length() - trimCount);
}
// Based on ES4 grammar proposed on July 10, 2008.
// http://wiki.ecmascript.org/doku.php?id=spec:spec
// Deliberately written to line up with the actual grammar rules,
// for maximum flexibility.
// TODO(nicksantos): The current implementation tries to maintain backwards
// compatibility with previous versions of the spec whenever we can.
// We should try to gradually withdraw support for these.
/**
* TypeExpressionAnnotation := TypeExpression |
* '{' TopLevelTypeExpression '}'
*/
private Node parseTypeExpressionAnnotation(JsDocToken token) {
if (token == JsDocToken.LC) {
skipEOLs();
Node typeNode = parseTopLevelTypeExpression(next());
if (typeNode != null) {
skipEOLs();
if (!match(JsDocToken.RC)) {
reportTypeSyntaxWarning("msg.jsdoc.missing.rc");
} else {
next();
}
}
return typeNode;
} else {
return parseTypeExpression(token);
}
}
/**
* ParamTypeExpressionAnnotation :=
* '{' OptionalParameterType '}' |
* '{' TopLevelTypeExpression '}' |
* '{' '...' TopLevelTypeExpression '}'
*
* OptionalParameterType :=
* TopLevelTypeExpression '='
*/
private Node parseParamTypeExpressionAnnotation(JsDocToken token) {
Preconditions.checkArgument(token == JsDocToken.LC);
skipEOLs();
boolean restArg = false;
token = next();
if (token == JsDocToken.ELLIPSIS) {
token = next();
if (token == JsDocToken.RC) {
// EMPTY represents the UNKNOWN type in the Type AST.
return wrapNode(Token.ELLIPSIS, new Node(Token.EMPTY));
}
restArg = true;
}
Node typeNode
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> 'null' | 'undefined' | TypeName
* | FunctionType | UnionType | RecordType | ArrayType
*/
private Node parseBasicTypeExpression(JsDocToken token) {
if (token == JsDocToken.STAR) {
return newNode(Token.STAR);
} else if (token == JsDocToken.LB) {
skipEOLs();
return parseArrayType(next());
} else if (token == JsDocToken.LC) {
skipEOLs();
return parseRecordType(next());
} else if (token == JsDocToken.LP) {
skipEOLs();
return parseUnionType(next());
} else if (token == JsDocToken.STRING) {
String string = stream.getString();
if ("function".equals(string)) {
skipEOLs();
return parseFunctionType(next());
} else if ("null".equals(string) || "undefined".equals(string)) {
return newStringNode(string);
} else {
return parseTypeName(token);
}
}
return reportGenericTypeSyntaxWarning();
}
/**
* TypeName := NameExpression | NameExpression TypeApplication
* TypeApplication := '.<' TypeExpressionList '>'
* TypeExpressionList := TypeExpression // a white lie
*/
private Node parseTypeName(JsDocToken token) {
if (token != JsDocToken.STRING) {
return reportGenericTypeSyntaxWarning();
}
String typeName = stream.getString();
while (match(JsDocToken.EOL) &&
typeName.charAt(typeName.length() - 1) == '.') {
skipEOLs();
if (match(JsDocToken.STRING)) {
next();
typeName += stream.getString();
}
}
Node typeNameNode = newStringNode(typeName);
if (match(JsDocToken.LT)) {
next();
skipEOLs();
Node memberType = parseTypeExpressionList(next());
if (memberType != null) {
typeNameNode.addChildToFront(memberType);
skipEOLs();
if (!match(JsDocToken.GT)) {
return reportTypeSyntaxWarning("msg.jsdoc.missing.gt");
}
next();
}
}
return typeNameNode;
}
/**
* FunctionType := 'function' FunctionSignatureType
* FunctionSignatureType :=
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> FieldType | FieldType ',' FieldTypeList
*/
private Node parseFieldTypeList(JsDocToken token) {
Node fieldTypeList = newNode(Token.LB);
do {
Node fieldType = parseFieldType(token);
if (fieldType == null) {
return null;
}
fieldTypeList.addChildToBack(fieldType);
skipEOLs();
if (!match(JsDocToken.COMMA)) {
break;
}
// Move to the comma token.
next();
// Move to the token passed the comma.
skipEOLs();
token = next();
} while (true);
return fieldTypeList;
}
/**
* FieldType := FieldName | FieldName ':' TypeExpression
*/
private Node parseFieldType(JsDocToken token) {
Node fieldName = parseFieldName(token);
if (fieldName == null) {
return null;
}
skipEOLs();
if (!match(JsDocToken.COLON)) {
return fieldName;
}
// Move to the colon.
next();
// Move to the token after the colon and parse
// the type expression.
skipEOLs();
Node typeExpression = parseTypeExpression(next());
if (typeExpression == null) {
return null;
}
Node fieldType = newNode(Token.COLON);
fieldType.addChildToBack(fieldName);
fieldType.addChildToBack(typeExpression);
return fieldType;
}
/**
* FieldName := NameExpression | StringLiteral | NumberLiteral |
* ReservedIdentifier
*/
private Node parseFieldName(JsDocToken token) {
switch (token) {
case STRING:
String string = stream.getString();
return newStringNode(string);
default:
return null;
}
}
private Node wrapNode(int type, Node n) {
return n == null ? null :
new Node(type, n, stream.getLineno(),
stream.getCharno()).clonePropsFrom(templateNode);
}
private Node newNode(int type) {
return new Node(type, stream.getLineno(),
stream.getCharno()).clonePropsFrom(templateNode);
}
private Node newStringNode(String s) {
return Node.newString(s, stream.getLineno(),
stream.getCharno()).clonePropsFrom(templateNode);
}
// This is
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Token token2) {
unreadToken = next();
return unreadToken == token1 || unreadToken == token2;
}
/**
* Gets the next token of the token stream or the buffered token if a matching
* was previously made.
*/
private JsDocToken next() {
if (unreadToken == NO_UNREAD_TOKEN) {
return stream.getJsDocToken();
} else {
return current();
}
}
/**
* Gets the current token, invalidating it in the process.
*/
private JsDocToken current() {
JsDocToken t = unreadToken;
unreadToken = NO_UNREAD_TOKEN;
return t;
}
/**
* Skips all EOLs and all empty lines in the JSDoc. Call this method if you
* want the JSDoc entry to span multiple lines.
*/
private void skipEOLs() {
while (match(JsDocToken.EOL)) {
next();
if (match(JsDocToken.STAR)) {
next();
}
}
}
/**
* Determines whether the parser has been populated with docinfo with a
* fileoverview tag.
*/
private boolean hasParsedFileOverviewDocInfo() {
return jsdocBuilder.isPopulatedWithFileOverview();
}
boolean hasParsedJSDocInfo() {
return jsdocBuilder.isPopulated();
}
JSDocInfo retrieveAndResetParsedJSDocInfo() {
return jsdocBuilder.build(sourceName);
}
/**
* Gets the fileoverview JSDocInfo, if any.
*/
JSDocInfo getFileOverviewJSDocInfo() {
return fileOverviewJSDocInfo;
}
/**
* Look ahead for a type annotation by advancing the character stream.
* Does not modify the token stream.
* This is kind of a hack, and is only necessary because we use the token
* stream to parse types, but need the underlying character stream to get
* JsDoc descriptions.
* @return Whether we found a type annotation.
*/
private boolean lookAheadForTypeAnnotation() {
boolean matchedLc = false;
int c;
while (true) {
c = stream.getChar();
if (c == ' ') {
continue;
} else if (c == '{') {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2007 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSTypeRegistry;
import com.google.javascript.rhino.jstype.ObjectType;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* CodingConvention defines a set of hooks to customize the behavior of the
* Compiler for a specific team/company.
*
*/
public class DefaultCodingConvention implements CodingConvention {
private static final long serialVersionUID = 1L;
@Override
public boolean isConstant(String variableName) {
return false;
}
@Override
public boolean isConstantKey(String variableName) {
return false;
}
@Override
public boolean isValidEnumKey(String key) {
return key != null && key.length() > 0;
}
@Override
public boolean isOptionalParameter(Node parameter) {
// be as lax as possible, but this must be mutually exclusive from
// var_args parameters.
return !isVarArgsParameter(parameter);
}
@Override
public boolean isVarArgsParameter(Node parameter) {
// be as lax as possible
return parameter.getParent().getLastChild() == parameter;
}
@Override
public boolean isExported(String name, boolean local) {
return local && name.startsWith("$super");
}
@Override
public boolean isExported(String name) {
return isExported(name, false) || isExported
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2007 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp.testing;
import com.google.javascript.jscomp.mozilla.rhino.ErrorReporter;
import com.google.javascript.jscomp.mozilla.rhino.EvaluatorException;
import junit.framework.Assert;
/**
* <p>An error reporter for testing that verifies that messages reported to the
* reporter are expected.</p>
*
* <p>Sample use</p>
* <pre>
* TestErrorReporter e =
* new TestErrorReporter(null, new String[] { "first warning" });
* ...
* assertTrue(e.hasEncounteredAllWarnings());
* </pre>
*
*/
public final class TestErrorReporter extends Assert implements ErrorReporter {
private final String[] errors;
private final String[] warnings;
private int errorsIndex = 0;
private int warningsIndex = 0;
public TestErrorReporter(String[] errors, String[] warnings) {
this.errors = errors;
this.warnings = warnings;
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset) {
if (errors != null && errorsIndex < errors.length) {
assertEquals(errors[errorsIndex++], message);
} else {
fail("extra error: " + message);
}
}
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset) {
if (warnings != null && warningsIndex < warnings.length) {
assertEquals(warnings[warningsIndex++], message);
} else {
fail("extra warning: " +
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> message);
}
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource, int lineOffset) {
return new EvaluatorException("JSCompiler test code: " + message);
}
/**
* Returns whether all warnings were reported to this reporter.
*/
public boolean hasEncounteredAllWarnings() {
return (warnings == null) ?
warningsIndex == 0 :
warnings.length == warningsIndex;
}
/**
* Returns whether all errors were reported to this reporter.
*/
public boolean hasEncounteredAllErrors() {
return (errors == null) ?
errorsIndex == 0 :
errors.length == errorsIndex;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2009 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Charsets;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
/**
* An abstract representation of a JavaScript source file, as input to
* JSCompiler.
*
* @author nicksantos@google.com (Nick Santos)
* @author moedinger@google.com (Andrew Moedinger)
*/
public class JSSourceFile extends SourceFile {
public static JSSourceFile fromFile(String fileName, Charset charSet) {
return new JSSourceFile(SourceFile.fromFile(fileName, charSet));
}
public static JSSourceFile fromFile(String fileName) {
return new JSSourceFile(SourceFile.fromFile(fileName, Charsets.UTF_8));
}
public static JSSourceFile fromFile(File file, Charset charSet) {
return new JSSourceFile(SourceFile.fromFile(file, charSet));
}
public static JSSourceFile fromFile(File file) {
return new JSSourceFile(SourceFile.fromFile(file, Charsets.UTF_8));
}
public static JSSourceFile fromCode(String fileName, String code) {
return new JSSourceFile(SourceFile.fromCode(fileName, code));
}
public static JSSourceFile fromInputStream(String fileName, InputStream s)
throws IOException {
return new JSSourceFile(SourceFile.fromInputStream
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(fileName, s));
}
public static JSSourceFile fromGenerator(String fileName,
Generator generator) {
return new JSSourceFile(SourceFile.fromGenerator(fileName, generator));
}
private SourceFile referenced;
private JSSourceFile(SourceFile referenced) {
super(referenced.getName());
this.referenced = referenced;
}
@Override
public String getCode() throws IOException {
return referenced.getCode();
}
@Override
public void clearCachedSource() {
referenced.clearCachedSource();
}
@Override
@VisibleForTesting
String getCodeNoCache() {
return referenced.getCodeNoCache();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Stub) {
// Incomplete definition
Definition definition = new ExternalNameOnlyDefinition(node);
nameDefinitionMultimap.put(name, definition);
definitionSiteMap.put(node,
new DefinitionSite(node,
definition,
traversal.getModule(),
traversal.inGlobalScope(),
inExterns));
}
}
}
}
/**
* @return Whether the node has a JSDoc that actually declares something.
*/
private boolean jsdocContainsDeclarations(Node node) {
JSDocInfo info = node.getJSDocInfo();
return (info != null && info.containsDeclaration());
}
}
private class UseSiteGatheringCallback extends AbstractPostOrderCallback {
@Override
public void visit(NodeTraversal traversal, Node node, Node parent) {
Collection<Definition> defs = getDefinitionsReferencedAt(node);
if (defs == null) {
return;
}
Definition first = defs.iterator().next();
String name = getSimplifiedName(first.getLValue());
Preconditions.checkNotNull(name);
nameUseSiteMultimap.put(
name,
new UseSite(node, traversal.getModule()));
}
}
/**
* @param use A use site to check.
* @return Whether the use is a call or new.
*/
static boolean isCallOrNewSite(UseSite use) {
Node call = use.node.getParent();
if (call == null) {
// The node has been removed from the AST.
return false;
}
// We need to make sure we're dealing with a call to the function we're
// optimizing. If the the first child of the parent is not the site, this
// is a nested call and it's a call to another function.
return NodeUtil.isCallOrNew(call) && call.getFirstChild() == use.node;
}
/**
* @return Whether the definition is directly exported.
*/
static boolean maybeExported(
AbstractCompiler compiler, Definition definition) {
// Assume an exported method result is used.
Node lValue = definition.getLValue();
if (lValue == null) {
return true;
}
String partialName;
if (NodeUtil.isGetProp(lValue)) {
partialName = lValue.getLastChild().getString
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> if (!isConnected(n1, edge, n2)) {
connect(n1, edge, n2);
}
}
/**
* Gets a node from the graph given a value. New nodes are created if that
* value has not been assigned a graph node. Values equality are compared
* using <code>Object.equals</code>.
*
* @param value The node's value.
* @return The corresponding node in the graph.
*/
public abstract GraphNode<N, E> createNode(N value);
/** Gets an immutable list of all nodes. */
public abstract Collection<GraphNode<N, E>> getNodes();
/** Gets an immutable list of all edges. */
public abstract List<GraphEdge<N, E>> getEdges();
/**
* Gets the degree of a node.
*
* @param value The node's value.
* @return The degree of the node.
*/
public abstract int getNodeDegree(N value);
public int getWeight(N value) {
return getNodeDegree(value);
}
/**
* Gets the neighboring nodes.
*
* @param value The node's value.
* @return A list of neighboring nodes.
*/
public abstract List<GraphNode<N, E>> getNeighborNodes(N value);
public abstract Iterator<GraphNode<N, E>> getNeighborNodesIterator(N value);
/**
* Retrieves an edge from the graph.
*
* @param n1 Node one.
* @param n2 Node two.
* @return The list of edges between those two values in the graph.
*/
public abstract List<GraphEdge<N, E>> getEdges(N n1, N n2);
/**
* Retrieves any edge from the graph.
*
* @param n1 Node one.
* @param n2 Node two.
* @return The first edges between those two values in the graph. null if
* there are none.
*/
public abstract GraphEdge<N, E> getFirstEdge(N n1, N n2);
/**
* Checks whether the node exists in the graph ({@link #createNode(Object)}
* has been called with that value).
*
* @param n Node.
* @return <code>true</code> if
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.
*/
public final void pushEdgeAnnotations() {
if (edgeAnnotationStack == null) {
edgeAnnotationStack = Lists.newLinkedList();
}
pushAnnotations(edgeAnnotationStack, getEdges());
}
/**
* Restores edges' annotation values to state before last
* {@link #pushEdgeAnnotations()}.
*/
public final void popEdgeAnnotations() {
Preconditions.checkNotNull(edgeAnnotationStack,
"Popping edge annotations without pushing.");
popAnnotations(edgeAnnotationStack);
}
/**
* A generic edge.
*
* @param <N> Value type that the graph node stores.
* @param <E> Value type that the graph edge stores.
*/
public interface GraphEdge<N, E> extends Annotatable {
/**
* Retrieves the edge's value.
*
* @return The value.
*/
E getValue();
GraphNode<N, E> getNodeA();
GraphNode<N, E> getNodeB();
}
/**
* A simple implementation of SubGraph that calculates adjacency by iterating
* over a node's neighbors.
*/
class SimpleSubGraph<N, E> implements SubGraph<N, E> {
private Graph<N, E> graph;
private List<GraphNode<N, E>> nodes = Lists.newArrayList();
SimpleSubGraph(Graph<N, E> graph) {
this.graph = graph;
}
public boolean isIndependentOf(N value) {
GraphNode<N, E> node = graph.getNode(value);
for (GraphNode<N, E> n : nodes) {
if (graph.getNeighborNodes(n.getValue()).contains(node)) {
return false;
}
}
return true;
}
public void addNode(N value) {
nodes.add(graph.getNodeOrFail(value));
}
}
/**
* Pushes a new list on stack and stores nodes annotations in the new list.
* Clears objects' annotations as well.
*/
private static void pushAnnotations(
Deque<GraphAnnotationState> stack,
Collection<? extends Annotatable> haveAnnotations) {
stack.push(new GraphAnnotationState(haveAnnotations.size()));
for (Annotatable h : haveAnnotations) {
stack.peek().add(new AnnotationState(h,
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ize("ERROR", Color.ERROR);
case WARNING: return maybeColorize("WARNING", Color.WARNING);
default: return level.toString();
}
}
private String maybeColorize(String text, Color color) {
if (!colorize) return text;
return color.getControlCharacter() +
text + Color.RESET.getControlCharacter();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>SError at a CheckLevel for a source file location.
* Private to avoid any entanglement with code outside of the compiler.
*/
private JSError(
String sourceName, @Nullable Node node, int lineno, int charno,
DiagnosticType type, CheckLevel level, String... arguments) {
this.type = type;
this.node = node;
this.description = type.format.format(arguments);
this.lineNumber = lineno;
this.charno = charno;
this.sourceName = sourceName;
this.level = level == null ? type.level : level;
}
/**
* Creates a JSError for a source file location. Private to avoid
* any entanglement with code outside of the compiler.
*/
private JSError(String sourceName, @Nullable Node node,
DiagnosticType type, String... arguments) {
this(sourceName,
node,
(node != null) ? node.getLineno() : -1,
(node != null) ? node.getCharno() : -1,
type, null, arguments);
}
public DiagnosticType getType() {
return type;
}
/**
* Format a message at the given level.
*
* @return the formatted message or {@code null}
*/
public String format(CheckLevel level, MessageFormatter formatter) {
switch (level) {
case ERROR:
return formatter.formatError(this);
case WARNING:
return formatter.formatWarning(this);
default:
return null;
}
}
@Override
public String toString() {
// TODO(user): remove custom toString.
return type.key + ". " + description + " at " +
(sourceName != null && sourceName.length() > 0 ?
sourceName : "(unknown source)") + " line " +
(lineNumber != -1 ? String.valueOf(lineNumber) : "(unknown line)") +
" : " + (charno != -1 ? String.valueOf(charno) : "(unknown column)");
}
/**
* Get the character number.
*/
public int getCharno() {
return charno;
}
@Override
public boolean equals(Object o) {
// Generated by Intellij IDEA
if (this == o) {
return true;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2010 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.collect.Maps;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import java.util.Map;
/**
* Filters warnings based on in-code {@code @suppress} annotations.
* @author nicksantos@google.com (Nick Santos)
*/
class SuppressDocWarningsGuard extends WarningsGuard {
/** Warnings guards for each suppressable warnings group, indexed by name. */
private final Map<String, DiagnosticGroupWarningsGuard> suppressors =
Maps.newHashMap();
/**
* The suppressable groups, indexed by name.
*/
SuppressDocWarningsGuard(Map<String, DiagnosticGroup> suppressableGroups) {
for (Map.Entry<String, DiagnosticGroup> entry :
suppressableGroups.entrySet()) {
suppressors.put(
entry.getKey(),
new DiagnosticGroupWarningsGuard(
entry.getValue(),
CheckLevel.OFF));
}
}
@Override
public CheckLevel level(JSError error) {
Node node = error.node;
if (node != null) {
for (Node current = node;
current != null;
current = current.getParent()) {
int type = current.getType();
JSDocInfo info = null;
// We only care about function annotations at the FUNCTION and SCRIPT
// level. Otherwise, the @suppress annotation has an implicit
// dependency on the exact structure of our AST, and that seems like
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> // a bad idea.
if (type == Token.FUNCTION) {
info = NodeUtil.getFunctionInfo(current);
} else if (type == Token.SCRIPT) {
info = current.getJSDocInfo();
}
if (info != null) {
for (String suppressor : info.getSuppressions()) {
WarningsGuard guard = suppressors.get(suppressor);
// Some @suppress tags are for other tools, and
// may not have a warnings guard.
if (guard != null) {
CheckLevel newLevel = guard.level(error);
if (newLevel != null) {
return newLevel;
}
}
}
}
}
}
return null;
}
@Override
public int getPriority() {
// Happens after path-based filtering, but before other times
// of filtering.
return WarningsGuard.Priority.SUPPRESS_DOC.value;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.google.javascript.jscomp.mozilla.rhino.ast.WhileLoop;
import com.google.javascript.jscomp.mozilla.rhino.ast.WithStatement;
/**
* Type safe dispatcher interface for use with new-style Rhino ASTs.
*
* The contents of this file was generated using a script; it is
* likely that the implementation below really belongs in a virtual
* typeSafeProcess(TypeSafeDispatcher) method implemented by all AST
* classes - which would make switching based on types and casting
* unnecessary.
*
*/
abstract class TypeSafeDispatcher<T> {
abstract T processArrayLiteral(ArrayLiteral literalNode);
abstract T processAssignment(Assignment assignmentNode);
abstract T processAstRoot(AstRoot rootNode);
abstract T processBlock(Block blockNode);
abstract T processBreakStatement(BreakStatement statementNode);
abstract T processCatchClause(CatchClause clauseNode);
abstract T processConditionalExpression(ConditionalExpression exprNode);
abstract T processContinueStatement(ContinueStatement statementNode);
abstract T processDoLoop(DoLoop loopNode);
abstract T processElementGet(ElementGet getNode);
abstract T processEmptyExpression(EmptyExpression exprNode);
abstract T processExpressionStatement(ExpressionStatement statementNode);
abstract T processForInLoop(ForInLoop loopNode);
abstract T processForLoop(ForLoop loopNode);
abstract T processFunctionCall(FunctionCall callNode);
abstract T processFunctionNode(FunctionNode functionNode);
abstract T processIfStatement(IfStatement statementNode);
abstract T processInfixExpression(InfixExpression exprNode);
abstract T processKeywordLiteral(KeywordLiteral literalNode);
abstract T processLabel(Label labelNode);
abstract T processLabeledStatement(LabeledStatement statementNode);
abstract T processName(Name nameNode);
abstract T processNewExpression(NewExpression exprNode);
abstract T processNumberLiteral(NumberLiteral literalNode);
abstract T processObjectLiteral(ObjectLiteral literalNode);
abstract T processObjectProperty(ObjectProperty propertyNode);
abstract T processParenthesizedExpression(ParenthesizedExpression exprNode);
abstract T processPropertyGet(PropertyGet getNode);
abstract T processRegExpLiteral(RegExpLiteral literalNode);
abstract T processReturnStatement(ReturnStatement statementNode);
abstract T processScope(Scope scopeNode);
abstract T processStringLiteral(StringLiteral literalNode);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>((PropertyGet) node);
case Token.HOOK:
return processConditionalExpression((ConditionalExpression) node);
case Token.IF:
return processIfStatement((IfStatement) node);
case Token.LABEL:
return processLabel((Label) node);
case Token.LP:
return processParenthesizedExpression((ParenthesizedExpression) node);
case Token.NAME:
return processName((Name) node);
case Token.NEW:
return processNewExpression((NewExpression) node);
case Token.NUMBER:
return processNumberLiteral((NumberLiteral) node);
case Token.OBJECTLIT:
return processObjectLiteral((ObjectLiteral) node);
case Token.REGEXP:
return processRegExpLiteral((RegExpLiteral) node);
case Token.RETURN:
return processReturnStatement((ReturnStatement) node);
case Token.SCRIPT:
return processAstRoot((AstRoot) node);
case Token.STRING:
return processStringLiteral((StringLiteral) node);
case Token.SWITCH:
return processSwitchStatement((SwitchStatement) node);
case Token.THROW:
return processThrowStatement((ThrowStatement) node);
case Token.TRY:
return processTryStatement((TryStatement) node);
case Token.CONST:
case Token.VAR:
if (node instanceof VariableDeclaration) {
return processVariableDeclaration((VariableDeclaration) node);
} else if (node instanceof VariableInitializer) {
return processVariableInitializer((VariableInitializer) node);
} else {
throw new IllegalStateException("Unexpected node type. class: " +
node.getClass() +
" type: " +
Token.typeToName(node.getType()));
}
case Token.WHILE:
return processWhileLoop((WhileLoop) node);
case Token.WITH:
return processWithStatement((WithStatement) node);
}
return processIllegalToken(node);
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2004 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.javascript.rhino.JSDocInfo;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import com.google.javascript.rhino.TokenStream;
import com.google.javascript.rhino.jstype.FunctionType;
import com.google.javascript.rhino.jstype.JSType;
import com.google.javascript.rhino.jstype.TernaryValue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nullable;
/**
* NodeUtil contains utilities that get properties from the Node object.
*
*/
public final class NodeUtil {
static final long MAX_POSITIVE_INTEGER_NUMBER = (long)Math.pow(2, 53);
final static String JSC_PROPERTY_NAME_FN = "JSCompiler_renameProperty";
// TODO(user): Eliminate this class and make all of the static methods
// instance methods of com.google.javascript.rhino.Node.
/** the set of builtin constructors that don't have
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> side effects. */
private static final Set<String> CONSTRUCTORS_WITHOUT_SIDE_EFFECTS =
new HashSet<String>(Arrays.asList(
"Array",
"Date",
"Error",
"Object",
"RegExp",
"XMLHttpRequest"));
// Utility class; do not instantiate.
private NodeUtil() {}
/**
* Gets the boolean value of a node that represents a expression. This method
* effectively emulates the <code>Boolean()</code> JavaScript cast function.
* Note: unlike getBooleanValue this function does not return UNKNOWN
* for expressions with side-effects.
*/
static TernaryValue getImpureBooleanValue(Node n) {
switch (n.getType()) {
case Token.ASSIGN:
case Token.COMMA:
// For ASSIGN and COMMA the value is the value of the RHS.
return getImpureBooleanValue(n.getLastChild());
case Token.NOT:
TernaryValue value = getImpureBooleanValue(n.getLastChild());
return value.not();
case Token.AND: {
TernaryValue lhs = getImpureBooleanValue(n.getFirstChild());
TernaryValue rhs = getImpureBooleanValue(n.getLastChild());
return lhs.and(rhs);
}
case Token.OR: {
TernaryValue lhs = getImpureBooleanValue(n.getFirstChild());
TernaryValue rhs = getImpureBooleanValue(n.getLastChild());
return lhs.or(rhs);
}
case Token.HOOK: {
TernaryValue trueValue = getImpureBooleanValue(
n.getFirstChild().getNext());
TernaryValue falseValue = getImpureBooleanValue(n.getLastChild());
if (trueValue.equals(falseValue)) {
return trueValue;
} else {
return TernaryValue.UNKNOWN;
}
}
case Token.ARRAYLIT:
case Token.OBJECTLIT:
// ignoring side-effects
return TernaryValue.TRUE;
default:
return getPureBooleanValue(n);
}
}
/**
* Gets the boolean value of a node that represents a literal. This method
* effectively emulates the <code>Boolean()</code> JavaScript cast function
* except it return UNKNOWN for known values with side-effects, use
* getExpressionBoolean
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Value if you don't care about side-effects.
*/
static TernaryValue getPureBooleanValue(Node n) {
switch (n.getType()) {
case Token.STRING:
return TernaryValue.forBoolean(n.getString().length() > 0);
case Token.NUMBER:
return TernaryValue.forBoolean(n.getDouble() != 0);
case Token.NOT:
return getPureBooleanValue(n.getLastChild()).not();
case Token.NULL:
case Token.FALSE:
case Token.VOID:
return TernaryValue.FALSE;
case Token.NAME:
String name = n.getString();
if ("undefined".equals(name)
|| "NaN".equals(name)) {
// We assume here that programs don't change the value of the keyword
// undefined to something other than the value undefined.
return TernaryValue.FALSE;
} else if ("Infinity".equals(name)) {
return TernaryValue.TRUE;
}
break;
case Token.TRUE:
case Token.REGEXP:
return TernaryValue.TRUE;
case Token.ARRAYLIT:
case Token.OBJECTLIT:
if (!mayHaveSideEffects(n)) {
return TernaryValue.TRUE;
}
}
return TernaryValue.UNKNOWN;
}
/**
* Gets the value of a node as a String, or null if it cannot be converted.
* When it returns a non-null String, this method effectively emulates the
* <code>String()</code> JavaScript cast function.
*/
static String getStringValue(Node n) {
// TODO(user): regex literals as well.
switch (n.getType()) {
case Token.STRING:
return n.getString();
case Token.NAME:
String name = n.getString();
if ("undefined".equals(name)
|| "Infinity".equals(name)
|| "NaN".equals(name)) {
return name;
}
break;
case Token.NUMBER:
return getStringValue(n.getDouble());
case Token.FALSE:
case Token.TRUE:
case Token.NULL:
return Node.tokenToName(n.getType());
case Token.VOID:
return "undefined";
case Token.NOT:
TernaryValue child = getPureBooleanValue(n
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.getFirstChild());
if (child != TernaryValue.UNKNOWN) {
return child.toBoolean(true) ? "false" : "true"; // reversed.
}
break;
case Token.ARRAYLIT:
return arrayToString(n);
case Token.OBJECTLIT:
return "[object Object]";
}
return null;
}
static String getStringValue(double value) {
long longValue = (long) value;
// Return "1" instead of "1.0"
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
/**
* When converting arrays to string using Array.prototype.toString or
* Array.prototype.join, the rules for conversion to String are different
* than converting each element individually. Specifically, "null" and
* "undefined" are converted to an empty string.
* @param n A node that is a member of an Array.
* @return The string representation.
*/
static String getArrayElementStringValue(Node n) {
return (NodeUtil.isNullOrUndefined(n) || n.getType() == Token.EMPTY)
? "" : getStringValue(n);
}
static String arrayToString(Node literal) {
Node first = literal.getFirstChild();
StringBuilder result = new StringBuilder();
int nextSlot = 0;
int nextSkipSlot = 0;
for (Node n = first; n != null; n = n.getNext()) {
String childValue = getArrayElementStringValue(n);
if (childValue == null) {
return null;
}
if (n != first) {
result.append(',');
}
result.append(childValue);
nextSlot++;
}
return result.toString();
}
/**
* Gets the value of a node as a Number, or null if it cannot be converted.
* When it returns a non-null Double, this method effectively emulates the
* <code>Number()</code> JavaScript cast function.
*/
static Double getNumberValue(Node n) {
switch (n.getType()) {
case Token.TRUE:
return 1.0;
case Token.FALSE:
case Token.NULL:
return 0.0;
case Token.NUMBER:
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> return n.getDouble();
case Token.VOID:
if (mayHaveSideEffects(n.getFirstChild())) {
return null;
} else {
return Double.NaN;
}
case Token.NAME:
// Check for known constants
String name = n.getString();
if (name.equals("undefined")) {
return Double.NaN;
}
if (name.equals("NaN")) {
return Double.NaN;
}
if (name.equals("Infinity")) {
return Double.POSITIVE_INFINITY;
}
return null;
case Token.NEG:
if (n.getChildCount() == 1 && n.getFirstChild().getType() == Token.NAME
&& n.getFirstChild().getString().equals("Infinity")) {
return Double.NEGATIVE_INFINITY;
}
return null;
case Token.NOT:
TernaryValue child = getPureBooleanValue(n.getFirstChild());
if (child != TernaryValue.UNKNOWN) {
return child.toBoolean(true) ? 0.0 : 1.0; // reversed.
}
break;
case Token.STRING:
return getStringNumberValue(n.getString());
case Token.ARRAYLIT:
case Token.OBJECTLIT:
String value = getStringValue(n);
return value != null ? getStringNumberValue(value) : null;
}
return null;
}
static Double getStringNumberValue(String rawJsString) {
if (rawJsString.contains("\u000b")) {
// vertical tab is not always whitespace
return null;
}
String s = trimJsWhiteSpace(rawJsString);
// return ScriptRuntime.toNumber(s);
if (s.length() == 0) {
return 0.0;
}
if (s.length() > 2
&& s.charAt(0) == '0'
&& (s.charAt(1) == 'x' || s.charAt(1) == 'X')) {
// Attempt to convert hex numbers.
try {
return Double.valueOf(Integer.parseInt(s.substring(2), 16));
} catch (NumberFormatException e) {
return Double.NaN;
}
}
if (s.length() > 3
&& (s.charAt(0) == '-' || s
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.charAt(0) == '+')
&& s.charAt(1) == '0'
&& (s.charAt(2) == 'x' || s.charAt(2) == 'X')) {
// hex numbers with explicit signs vary between browsers.
return null;
}
// FireFox and IE treat the "Infinity" differently. FireFox is case
// insensitive, but IE treats "infinity" as NaN. So leave it alone.
if (s.equals("infinity")
|| s.equals("-infinity")
|| s.equals("+infinity")) {
return null;
}
try {
return Double.parseDouble(s);
} catch (NumberFormatException e) {
return Double.NaN;
}
}
static String trimJsWhiteSpace(String s) {
int start = 0;
int end = s.length();
while (end > 0
&& isStrWhiteSpaceChar(s.charAt(end - 1)) == TernaryValue.TRUE) {
end--;
}
while (start < end
&& isStrWhiteSpaceChar(s.charAt(start)) == TernaryValue.TRUE) {
start++;
}
return s.substring(start, end);
}
/**
* Copied from Rhino's ScriptRuntime
*/
static TernaryValue isStrWhiteSpaceChar(int c) {
switch (c) {
case '\u000B': // <VT>
return TernaryValue.UNKNOWN; // IE says "no", EcmaScript says "yes"
case ' ': // <SP>
case '\n': // <LF>
case '\r': // <CR>
case '\t': // <TAB>
case '\u00A0': // <NBSP>
case '\u000C': // <FF>
case '\u2028': // <LS>
case '\u2029': // <PS>
case '\uFEFF': // <BOM>
return TernaryValue.TRUE;
default:
return (Character.getType(c) == Character.SPACE_SEPARATOR)
? TernaryValue.TRUE : TernaryValue.FALSE;
}
}
/**
* Gets the function's name. This method recognizes five forms:
* <ul>
*
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> <li>{@code function name() ...}</li>
* <li>{@code var name = function() ...}</li>
* <li>{@code qualified.name = function() ...}</li>
* <li>{@code var name2 = function name1() ...}</li>
* <li>{@code qualified.name2 = function name1() ...}</li>
* </ul>
* In two last cases with named function expressions, the second name is
* returned (the variable of qualified name).
*
* @param n a node whose type is {@link Token#FUNCTION}
* @return the function's name, or {@code null} if it has no name
*/
static String getFunctionName(Node n) {
Node parent = n.getParent();
String name = n.getFirstChild().getString();
switch (parent.getType()) {
case Token.NAME:
// var name = function() ...
// var name2 = function name1() ...
return parent.getString();
case Token.ASSIGN:
// qualified.name = function() ...
// qualified.name2 = function name1() ...
return parent.getFirstChild().getQualifiedName();
default:
// function name() ...
return name != null && name.length() != 0 ? name : null;
}
}
/**
* Gets the function's name. This method recognizes the forms:
* <ul>
* <li>{@code {'name': function() ...}}</li>
* <li>{@code {name: function() ...}}</li>
* <li>{@code function name() ...}</li>
* <li>{@code var name = function() ...}</li>
* <li>{@code qualified.name = function() ...}</li>
* <li>{@code var name2 = function name1() ...}</li>
* <li>{@code qualified.name2 = function name1() ...}</li>
* </ul>
*
* @param n a node whose type is {@link Token#FUNCTION}
* @return the function's name, or {@code null} if it has no name
*/
static String getNearestFunctionName(Node n) {
String name = getFunctionName(n);
if (name != null) {
return
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> name;
}
// Check for the form { 'x' : function() { } }
Node parent = n.getParent();
switch (parent.getType()) {
case Token.SET:
case Token.GET:
case Token.STRING:
// Return the name of the literal's key.
return parent.getString();
case Token.NUMBER:
return getStringValue(parent);
}
return null;
}
/**
* Returns true if this is an immutable value.
*/
static boolean isImmutableValue(Node n) {
switch (n.getType()) {
case Token.STRING:
case Token.NUMBER:
case Token.NULL:
case Token.TRUE:
case Token.FALSE:
return true;
case Token.NOT:
return isImmutableValue(n.getFirstChild());
case Token.VOID:
case Token.NEG:
return isImmutableValue(n.getFirstChild());
case Token.NAME:
String name = n.getString();
// We assume here that programs don't change the value of the keyword
// undefined to something other than the value undefined.
return "undefined".equals(name)
|| "Infinity".equals(name)
|| "NaN".equals(name);
}
return false;
}
/**
* Returns true if this is a literal value. We define a literal value
* as any node that evaluates to the same thing regardless of when or
* where it is evaluated. So /xyz/ and [3, 5] are literals, but
* the name a is not.
*
* Function literals do not meet this definition, because they
* lexically capture variables. For example, if you have
* <code>
* function() { return a; }
* </code>
* If it is evaluated in a different scope, then it
* captures a different variable. Even if the function did not read
* any captured vairables directly, it would still fail this definition,
* because it affects the lifecycle of variables in the enclosing scope.
*
* However, a function literal with respect to a particular scope is
* a literal.
*
* @param includeFunctions If true, all function expressions will be
* treated as literals.
*/
static boolean isLiteralValue(Node n, boolean includeFunctions) {
switch (n.getType
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.hasFinally(tryNode));
node.detachFromParent();
} else if (isTryCatchNodeContainer(node)) {
// The container node itself can't be removed, but the contained CATCH
// can if there is a 'finally' clause
Node tryNode = node.getParent();
Preconditions.checkState(NodeUtil.hasFinally(tryNode));
node.detachChildren();
} else if (node.getType() == Token.BLOCK) {
// Simply empty the block. This maintains source location and
// "synthetic"-ness.
node.detachChildren();
} else if (isStatementBlock(parent)
|| isSwitchCase(node)) {
// A statement in a block can simply be removed.
parent.removeChild(node);
} else if (parent.getType() == Token.VAR) {
if (parent.hasMoreThanOneChild()) {
parent.removeChild(node);
} else {
// Remove the node from the parent, so it can be reused.
parent.removeChild(node);
// This would leave an empty VAR, remove the VAR itself.
removeChild(parent.getParent(), parent);
}
} else if (parent.getType() == Token.LABEL
&& node == parent.getLastChild()) {
// Remove the node from the parent, so it can be reused.
parent.removeChild(node);
// A LABEL without children can not be referred to, remove it.
removeChild(parent.getParent(), parent);
} else if (parent.getType() == Token.FOR
&& parent.getChildCount() == 4) {
// Only Token.FOR can have an Token.EMPTY other control structure
// need something for the condition. Others need to be replaced
// or the structure removed.
parent.replaceChild(node, new Node(Token.EMPTY));
} else {
throw new IllegalStateException("Invalid attempt to remove node: " +
node.toString() + " of "+ parent.toString());
}
}
/**
* Add a finally block if one does not exist.
*/
static void maybeAddFinally(Node tryNode) {
Preconditions.checkState(tryNode.getType() == Token.TRY);
if (!NodeUtil.hasFinally(tryNode)) {
tryNode.addChildrenToBack(new Node(Token.BLOCK)
.copyInformationFrom(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> @param parent Parent of the node
* @return True if n is the left hand of an assign
*/
static boolean isLhs(Node n, Node parent) {
return (parent.getType() == Token.ASSIGN && parent.getFirstChild() == n) ||
parent.getType() == Token.VAR;
}
/**
* Determines whether a node represents an object literal key
* (e.g. key1 in {key1: value1, key2: value2}).
*
* @param node A node
* @param parent The node's parent
*/
static boolean isObjectLitKey(Node node, Node parent) {
switch (node.getType()) {
case Token.NUMBER:
case Token.STRING:
return parent.getType() == Token.OBJECTLIT;
case Token.GET:
case Token.SET:
return true;
}
return false;
}
/**
* Get the name of an object literal key.
*
* @param key A node
*/
static String getObjectLitKeyName(Node key) {
switch (key.getType()) {
case Token.NUMBER:
return NodeUtil.getStringValue(key);
case Token.STRING:
case Token.GET:
case Token.SET:
return key.getString();
}
throw new IllegalStateException("Unexpected node type: " + key);
}
/**
* @param key A OBJECTLIT key node.
* @return The type expected when using the key.
*/
static JSType getObjectLitKeyTypeFromValueType(Node key, JSType valueType) {
if (valueType != null) {
switch (key.getType()) {
case Token.GET:
// GET must always return a function type.
if (valueType.isFunctionType()) {
FunctionType fntype = ((FunctionType) valueType);
valueType = fntype.getReturnType();
} else {
return null;
}
break;
case Token.SET:
if (valueType.isFunctionType()) {
// SET must always return a function type.
FunctionType fntype = ((FunctionType) valueType);
Node param = fntype.getParametersNode().getFirstChild();
// SET function must always have one parameter.
valueType = param.getJSType();
} else {
return null;
}
break;
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>return The node created.
*/
static Node newName(
CodingConvention convention, String name,
Node basisNode, String originalName) {
Node nameNode = newName(convention, name, basisNode);
nameNode.putProp(Node.ORIGINALNAME_PROP, originalName);
return nameNode;
}
/** Test if all characters in the string are in the Basic Latin (aka ASCII)
* character set - that they have UTF-16 values equal to or below 0x7f.
* This check can find which identifiers with Unicode characters need to be
* escaped in order to allow resulting files to be processed by non-Unicode
* aware UNIX tools and editors.
* *
* See http://en.wikipedia.org/wiki/Latin_characters_in_Unicode
* for more on Basic Latin.
*
* @param s The string to be checked for ASCII-goodness.
*
* @return True if all characters in the string are in Basic Latin set.
*/
static boolean isLatin(String s) {
char LARGEST_BASIC_LATIN = 0x7f;
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c > LARGEST_BASIC_LATIN) {
return false;
}
}
return true;
}
/**
* Determines whether the given name can appear on the right side of
* the dot operator. Many properties (like reserved words) cannot.
*/
static boolean isValidPropertyName(String name) {
return TokenStream.isJSIdentifier(name) &&
!TokenStream.isKeyword(name) &&
// no Unicode escaped characters - some browsers are less tolerant
// of Unicode characters that might be valid according to the
// language spec.
// Note that by this point, unicode escapes have been converted
// to UTF-16 characters, so we're only searching for character
// values, not escapes.
isLatin(name);
}
private static class VarCollector implements Visitor {
final Map<String, Node> vars = Maps.newLinkedHashMap();
public void visit(Node n) {
if (n.getType() == Token.NAME) {
Node parent = n.getParent();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
if (parent != null && parent.getType() == Token.VAR) {
String name = n.getString();
if (!vars.containsKey(name)) {
vars.put(name, n);
}
}
}
}
}
/**
* Retrieves vars declared in the current node tree, excluding descent scopes.
*/
public static Collection<Node> getVarsDeclaredInBranch(Node root) {
VarCollector collector = new VarCollector();
visitPreOrder(
root,
collector,
new MatchNotFunction());
return collector.vars.values();
}
/**
* @return {@code true} if the node an assignment to a prototype property of
* some constructor.
*/
static boolean isPrototypePropertyDeclaration(Node n) {
if (!isExprAssign(n)) {
return false;
}
return isPrototypeProperty(n.getFirstChild().getFirstChild());
}
static boolean isPrototypeProperty(Node n) {
String lhsString = n.getQualifiedName();
if (lhsString == null) {
return false;
}
int prototypeIdx = lhsString.indexOf(".prototype.");
return prototypeIdx != -1;
}
/**
* @return The class name part of a qualified prototype name.
*/
static Node getPrototypeClassName(Node qName) {
Node cur = qName;
while (isGetProp(cur)) {
if (cur.getLastChild().getString().equals("prototype")) {
return cur.getFirstChild();
} else {
cur = cur.getFirstChild();
}
}
return null;
}
/**
* @return The string property name part of a qualified prototype name.
*/
static String getPrototypePropertyName(Node qName) {
String qNameStr = qName.getQualifiedName();
int prototypeIdx = qNameStr.lastIndexOf(".prototype.");
int memberIndex = prototypeIdx + ".prototype".length() + 1;
return qNameStr.substring(memberIndex);
}
/**
* Create a node for an empty result expression:
* "void 0"
*/
static Node newUndefinedNode(Node srcReferenceNode) {
Node node = new Node(Token.VOID, Node.newNumber(0));
if (srcReferenceNode != null) {
node.copyInformationFromForTree(srcReference
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Node);
}
return node;
}
/**
* Create a VAR node containing the given name and initial value expression.
*/
static Node newVarNode(String name, Node value) {
Node nodeName = Node.newString(Token.NAME, name);
if (value != null) {
Preconditions.checkState(value.getNext() == null);
nodeName.addChildToBack(value);
nodeName.copyInformationFrom(value);
}
Node var = new Node(Token.VAR, nodeName)
.copyInformationFrom(nodeName);
return var;
}
/**
* A predicate for matching name nodes with the specified node.
*/
private static class MatchNameNode implements Predicate<Node>{
final String name;
MatchNameNode(String name){
this.name = name;
}
public boolean apply(Node n) {
return n.getType() == Token.NAME
&& n.getString().equals(name);
}
}
/**
* A predicate for matching nodes with the specified type.
*/
static class MatchNodeType implements Predicate<Node>{
final int type;
MatchNodeType(int type){
this.type = type;
}
public boolean apply(Node n) {
return n.getType() == type;
}
}
/**
* A predicate for matching var or function declarations.
*/
static class MatchDeclaration implements Predicate<Node> {
public boolean apply(Node n) {
return isFunctionDeclaration(n) || n.getType() == Token.VAR;
}
}
/**
* A predicate for matching anything except function nodes.
*/
static class MatchNotFunction implements Predicate<Node>{
public boolean apply(Node n) {
return !isFunction(n);
}
}
/**
* A predicate for matching statements without exiting the current scope.
*/
static class MatchShallowStatement implements Predicate<Node>{
public boolean apply(Node n) {
Node parent = n.getParent();
return n.getType() == Token.BLOCK
|| (!isFunction(n) && (parent == null
|| isControlStructure(parent)
|| isStatementBlock(parent)));
}
}
/**
* Finds the number of times a type is referenced within the node tree.
*/
static int getNodeTypeReferenceCount(
Node node, int type, Predicate<Node>
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
* <p>Determining whether a variable is constant has three steps:
* <ol>
* <li>In CodingConventionAnnotator, any name that matches the
* {@link CodingConvention#isConstant(String)} is annotated with an
* IS_CONSTANT_NAME property.
* <li>The normalize pass renames any variable with the IS_CONSTANT_NAME
* annotation and that is initialized to a constant value with
* a variable name inlucding $$constant.
* <li>Return true here if the variable includes $$constant in its name.
* </ol>
*
* @param node A NAME or STRING node
* @return True if the variable is constant
*/
static boolean isConstantName(Node node) {
return node.getBooleanProp(Node.IS_CONSTANT_NAME);
}
/** Whether the given name is constant by coding convention. */
static boolean isConstantByConvention(
CodingConvention convention, Node node, Node parent) {
String name = node.getString();
if (parent.getType() == Token.GETPROP &&
node == parent.getLastChild()) {
return convention.isConstantKey(name);
} else if (isObjectLitKey(node, parent)) {
return convention.isConstantKey(name);
} else {
return convention.isConstant(name);
}
}
/**
* @param nameNode A name node
* @return The JSDocInfo for the name node
*/
static JSDocInfo getInfoForNameNode(Node nameNode) {
JSDocInfo info = null;
Node parent = null;
if (nameNode != null) {
info = nameNode.getJSDocInfo();
parent = nameNode.getParent();
}
if (info == null && parent != null &&
((parent.getType() == Token.VAR && parent.hasOneChild()) ||
parent.getType() == Token.FUNCTION)) {
info = parent.getJSDocInfo();
}
return info;
}
/**
* Get the JSDocInfo for a function.
*/
static JSDocInfo getFunctionInfo(Node n) {
Preconditions.checkState(n.getType() == Token.FUNCTION);
JSDocInfo fnInfo = n.getJSDocInfo();
if (fn
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Info == null && NodeUtil.isFunctionExpression(n)) {
// Look for the info on other nodes.
Node parent = n.getParent();
if (parent.getType() == Token.ASSIGN) {
// on ASSIGNs
fnInfo = parent.getJSDocInfo();
} else if (parent.getType() == Token.NAME) {
// on var NAME = function() { ... };
fnInfo = parent.getParent().getJSDocInfo();
}
}
return fnInfo;
}
/**
* @param n The node.
* @return The source name property on the node or its ancestors.
*/
static String getSourceName(Node n) {
String sourceName = null;
while (sourceName == null && n != null) {
sourceName = (String) n.getProp(Node.SOURCENAME_PROP);
n = n.getParent();
}
return sourceName;
}
/**
* A new CALL node with the "FREE_CALL" set based on call target.
*/
static Node newCallNode(Node callTarget, Node... parameters) {
boolean isFreeCall = isName(callTarget);
Node call = new Node(Token.CALL, callTarget);
call.putBooleanProp(Node.FREE_CALL, isFreeCall);
for (Node parameter : parameters) {
call.addChildToBack(parameter);
}
return call;
}
/**
* @return Whether the node is known to be a value that is not referenced
* elsewhere.
*/
static boolean evaluatesToLocalValue(Node value) {
return evaluatesToLocalValue(value, Predicates.<Node>alwaysFalse());
}
/**
* @param locals A predicate to apply to unknown local values.
* @return Whether the node is known to be a value that is not a reference
* outside the expression scope.
*/
static boolean evaluatesToLocalValue(Node value, Predicate<Node> locals) {
switch (value.getType()) {
case Token.ASSIGN:
// A result that is aliased by a non-local name, is the effectively the
// same as returning a non-local name, but this doesn't matter if the
// value is immutable.
return NodeUtil.isImmutableValue(value.getLastChild())
|| (locals.apply
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(value)
&& evaluatesToLocalValue(value.getLastChild(), locals));
case Token.COMMA:
return evaluatesToLocalValue(value.getLastChild(), locals);
case Token.AND:
case Token.OR:
return evaluatesToLocalValue(value.getFirstChild(), locals)
&& evaluatesToLocalValue(value.getLastChild(), locals);
case Token.HOOK:
return evaluatesToLocalValue(value.getFirstChild().getNext(), locals)
&& evaluatesToLocalValue(value.getLastChild(), locals);
case Token.INC:
case Token.DEC:
if (value.getBooleanProp(Node.INCRDECR_PROP)) {
return evaluatesToLocalValue(value.getFirstChild(), locals);
} else {
return true;
}
case Token.THIS:
return locals.apply(value);
case Token.NAME:
return isImmutableValue(value) || locals.apply(value);
case Token.GETELEM:
case Token.GETPROP:
// There is no information about the locality of object properties.
return locals.apply(value);
case Token.CALL:
return callHasLocalResult(value)
|| isToStringMethodCall(value)
|| locals.apply(value);
case Token.NEW:
return newHasLocalResult(value)
|| locals.apply(value);
case Token.FUNCTION:
case Token.REGEXP:
case Token.ARRAYLIT:
case Token.OBJECTLIT:
// Literals objects with non-literal children are allowed.
return true;
case Token.DELPROP:
case Token.IN:
// TODO(johnlenz): should IN operator be included in #isSimpleOperator?
return true;
default:
// Other op force a local value:
// x = '' + g (x is now an local string)
// x -= g (x is now an local number)
if (isAssignmentOp(value)
|| isSimpleOperator(value)
|| isImmutableValue(value)) {
return true;
}
throw new IllegalStateException(
"Unexpected expression node" + value +
"\n parent:" + value.getParent());
}
}
/**
* Given the first sibling, this returns the nth
* sibling or null if no such sibling exists.
* This is like "getChildAtIndex" but returns null for non-existent indexes.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
*/
private static Node getNthSibling(Node first, int index) {
Node sibling = first;
while (index != 0 && sibling != null) {
sibling = sibling.getNext();
index--;
}
return sibling;
}
/**
* Given the function, this returns the nth
* argument or null if no such parameter exists.
*/
static Node getArgumentForFunction(Node function, int index) {
Preconditions.checkState(isFunction(function));
return getNthSibling(
function.getFirstChild().getNext().getFirstChild(), index);
}
/**
* Given the new or call, this returns the nth
* argument of the call or null if no such argument exists.
*/
static Node getArgumentForCallOrNew(Node call, int index) {
Preconditions.checkState(isCallOrNew(call));
return getNthSibling(
call.getFirstChild().getNext(), index);
}
private static boolean isToStringMethodCall(Node call) {
Node getNode = call.getFirstChild();
if (isGet(getNode)) {
Node propNode = getNode.getLastChild();
return isString(propNode) && "toString".equals(propNode.getString());
}
return false;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> keeps logging events and never clears them).
* This number is arbitrary and can be increased if necessary (though
* if there are more than 1000 events then the Tracer is probably being
* misused).
*/
static final int MAX_TRACE_SIZE = 1000;
/**
* For unit testing. Can't use {@link com.google.common.time.Clock} because
* this code is in base and has minimal dependencies.
*/
static interface InternalClock {
long currentTimeMillis();
}
/**
* Default clock that calls through to the system clock. Can be overridden
* in unit tests.
*/
static InternalClock clock = new InternalClock() {
public long currentTimeMillis() {
return System.currentTimeMillis();
}
};
/**
* Create and start a tracer.
* Both type and comment may be null. See class comment for usage.
*
* @param type The type for totalling
* @param comment Comment about this tracer
*/
Tracer(@Nullable String type, @Nullable String comment) {
this.type = type;
this.comment = comment == null ? "" : comment;
startTimeMs = clock.currentTimeMillis();
startThread = Thread.currentThread();
if (!extraTracingStatistics.isEmpty()) {
int size = extraTracingStatistics.size();
extraTracingValues = new long[size];
int i = 0;
for (TracingStatistic tracingStatistic : extraTracingStatistics) {
extraTracingValues[i] = tracingStatistic.start(startThread);
i++;
}
}
ThreadTrace trace = getThreadTrace();
// Do nothing if the current thread trace wasn't initialized.
if (!trace.isInitialized()) {
return;
}
// Check if we are creating too many Tracers.
if (trace.events.size() >= MAX_TRACE_SIZE) {
logger.log(Level.WARNING,
"Giant thread trace. Too many Tracers created. "
+ "Clearing to avoid memory leak.",
new Throwable(trace.toString()));
trace.truncateEvents();
}
// Check if we forgot to close the Tracers.
if (trace.outstandingEvents.size() >= MAX_TRACE_SIZE) {
logger.log(Level.WARNING,
"Too many outstanding Tracers. Tracer
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.stop() is missing "
+ "or Tracer.stop() is not wrapped in a "
+ "try/finally block. "
+ "Clearing to avoid memory leak.",
new Throwable(trace.toString()));
trace.truncateOutstandingEvents();
}
trace.startEvent(this);
}
/**
* Create a tracer that isn't summed as part of a total
*
* @param comment Comment about this tracer
*/
Tracer(String comment) {
this(null, comment);
}
/**
* Construct a tracer whose type is based on the short name of the object
* @param object Object to use as type name
* @param comment A comment
* @return new Tracer.
*/
static Tracer shortName(Object object, String comment) {
if (object == null) {
return new Tracer(comment);
}
return new Tracer(object.getClass().getSimpleName(), comment);
}
/**
* Converts 'v' to a string and pads it with up to 16 spaces for
* improved alignment.
* @param v The value to convert.
* @param digits_column_width The desired with of the string.
*/
private static String longToPaddedString(long v, int digits_column_width) {
int digit_width = numDigits(v);
StringBuilder sb = new StringBuilder();
appendSpaces(sb, digits_column_width - digit_width);
sb.append(v);
return sb.toString();
}
/**
* Gets the number of digits in an integer when printed in base 10. Assumes
* a positive integer.
* @param n The value.
* @return The number of digits in the string.
*/
private static int numDigits(long n) {
int i = 0;
do {
i++;
n = n / 10;
} while (n > 0);
return i;
}
/**
* Gets a string of spaces of the length specified.
* @param sb The string builder to append to.
* @param numSpaces The number of spaces in the string.
*/
@VisibleForTesting
static void appendSpaces(StringBuilder sb, int numSpaces) {
if (numSpaces > 16) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> silence_threshold) {
Preconditions.checkState(Thread.currentThread() == startThread);
ThreadTrace trace = getThreadTrace();
// Do nothing if the thread trace was not initialized.
if (!trace.isInitialized()) {
return 0;
}
stopTimeMs = clock.currentTimeMillis();
if (extraTracingValues != null) {
// We use extraTracingValues.length rather than
// extraTracingStatistics.size() because a new statistic may
// have been added
for (int i = 0; i < extraTracingValues.length; i++) {
long value = extraTracingStatistics.get(i).stop(startThread);
extraTracingValues[i] = value - extraTracingValues[i];
}
}
// Do nothing if the thread trace was not initialized.
if (!trace.isInitialized()) {
return 0;
}
trace.endEvent(this, silence_threshold);
return stopTimeMs - startTimeMs;
}
/** Stop the trace using the default silence_threshold
*
* @return The time that this trace actually ran.
*/
long stop() {
return stop(-1);
}
@Override public String toString() {
if (type == null) {
return comment;
} else {
return "[" + type + "] " + comment;
}
}
static void setDefaultSilenceThreshold(int threshold) {
getThreadTrace().defaultSilenceThreshold = threshold;
}
/**
* Initialize the trace associated with the current thread by clearing
* out any existing trace. There shouldn't be a trace so if one is
* found we log it as an error.
*/
static void initCurrentThreadTrace() {
ThreadTrace events = getThreadTrace();
if (!events.isEmpty()) {
logger.log(Level.WARNING,
"Non-empty timer log:\n" + events,
new Throwable());
clearThreadTrace();
// Grab a new thread trace if we find a previous non-empty ThreadTrace.
events = getThreadTrace();
}
// Mark the thread trace as initialized.
events.init();
}
static void initCurrentThreadTrace(int default_silence_threshold) {
initCurrentThreadTrace();
setDefaultSilenceThreshold(default_silence_threshold);
}
/**
* Returns a timer report similar
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> to the one described in the class comment.
*
* @return The timer report as a string
*/
static String getCurrentThreadTraceReport() {
return getThreadTrace().toString();
}
/**
* Logs a timer report similar to the one described in the class comment.
*/
static void logCurrentThreadTrace() {
ThreadTrace trace = getThreadTrace();
// New threads must call Tracer.initCurrentThreadTrace() before Tracer
// statistics are gathered. This is a recent change (Jun 2007) that
// prevents spurious Third Eye messages when an application uses a class in
// a different package that happens to call Tracer without knowledge of the
// application authors.
if (!trace.isInitialized()) {
logger.log(Level.WARNING,
"Tracer log requested for this thread but was not "
+ "initialized using Tracer.initCurrentThreadTrace().",
new Throwable());
return;
}
if (!trace.isEmpty()) {
logger.log(Level.INFO, "timers:\n{0}", getCurrentThreadTraceReport());
}
}
/**
* Throw away any Trace associated with the current thread.
*/
static void clearCurrentThreadTrace() {
clearThreadTrace();
}
/**
* logCurrentThreadTrace() then clearCurrentThreadTrace()
*/
static void logAndClearCurrentThreadTrace() {
logCurrentThreadTrace();
clearThreadTrace();
}
/**
* Sets whether pretty printing is enabled. See class-level comment. This
* only affects tracers created after this is called.
* @param enabled Whether to enable pretty printing.
*/
static void setPrettyPrint(boolean enabled) {
defaultPrettyPrint = enabled;
}
/** Statistics for a given tracer type */
static final class Stat {
private int count;
private int silent;
private int clockTime;
private int[] extraInfo;
/** total count of tracers of a type, including silent
*
* @return total count of tracers, including silent tracers
*/
int getCount() { return count; }
/** total count of silent tracers of a type
*
* @return total count of silent tracers
*/
int getSilentCount() { return silent; }
/** total time spent in tracers of a
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> type, in ms
*
* @return total time spent in tracer, in ms
*/
int getTotalTime() { return clockTime; }
/** total time spent doing additional things that we are clocking */
@VisibleForTesting
int getExtraInfo(int index) {
return index >= extraInfo.length ? 0 : extraInfo[index];
}
}
/**
* This map tracks counts of tracers for each type over all time.
*/
private static @Nullable AtomicTracerStatMap typeToCountMap;
/**
* This map tracks counts of silent tracers for each type over all time.
*/
private static @Nullable AtomicTracerStatMap typeToSilentMap;
/**
* This map tracks time (ms) for each type over all time.
*/
private static @Nullable AtomicTracerStatMap typeToTimeMap;
/**
* This method MUST be called before getTypeToCountMap (and friends)
* will return a valid map. This is because computing this information
* imposes a synchronization penalty on every Tracer that is stopped.
*/
static synchronized void enableTypeMaps() {
if (typeToCountMap == null) {
typeToCountMap = new AtomicTracerStatMap();
typeToSilentMap = new AtomicTracerStatMap();
typeToTimeMap = new AtomicTracerStatMap();
}
}
/**
* Used for exporting this data via varz. Accesses to this
* map must be synchronized on the map. If enableTypeMaps has not
* been called, this will return null.
*/
static @Nullable Map<String, Long> getTypeToCountMap() {
return typeToCountMap != null ? typeToCountMap.getMap() : null;
}
/**
* Used for exporting this data via varz. Accesses to this
* map must be synchronized on the map. If enableTypeMaps has not
* been called, this will return null.
*/
static @Nullable Map<String, Long> getTypeToSilentMap() {
return typeToSilentMap != null ? typeToSilentMap.getMap() : null;
}
/**
* Used for exporting this data via varz. Accesses to this
* map must be synchronized on the map. If enableTypeMaps has not
* been called,
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> this will return null.
*/
static @Nullable Map<String, Long> getTypeToTimeMap() {
return typeToTimeMap != null ? typeToTimeMap.getMap() : null;
}
/** Gets the Stat for a tracer type; never returns null */
static Stat getStatsForType(String type) {
Stat stat = getThreadTrace().stats.get(type);
return stat != null ? stat : ZERO_STAT;
}
private static final Stat ZERO_STAT = new Stat();
/** Return the sec.ms part of time (if time = "20:06:11.566", "11.566") */
private static String formatTime(long time) {
int sec = (int) ((time / 1000) % 60);
int ms = (int) (time % 1000);
return String.format("%02d.%03d", sec, ms);
}
/** An event is created every time a Tracer is created or stopped */
private static final class Event {
boolean isStart; // else is_stop
Tracer tracer;
Event(boolean start, Tracer t) {
isStart = start;
tracer = t;
}
long eventTime() {
return isStart ? tracer.startTimeMs : tracer.stopTimeMs;
}
/**
* Converts the event to a formatted string.
* @param prevEventTime The time of the previous event which appears at
* the left most part of the trace line.
* @param indent The indentation to put before the tracer to show the
* hieararchy.
* @param digitsColWidth How many characters the digits should use.
* @return The formatted string.
*/
String toString(long prevEventTime, String indent, int digitsColWidth) {
StringBuilder sb = new StringBuilder(120);
if (prevEventTime == -1) {
appendSpaces(sb, digitsColWidth);
} else {
sb.append(longToPaddedString(
eventTime() - prevEventTime, digitsColWidth));
}
sb.append(' ');
sb.append(formatTime(eventTime()));
if (isStart) {
sb.append(" Start ");
appendSpaces(sb, digits
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ColWidth);
sb.append(" ");
} else {
sb.append(" Done ");
long delta = tracer.stopTimeMs - tracer.startTimeMs;
sb.append(longToPaddedString(delta, digitsColWidth));
sb.append(" ms ");
if (tracer.extraTracingValues != null) {
for (int i = 0; i < tracer.extraTracingValues.length; i++) {
delta = tracer.extraTracingValues[i];
sb.append(String.format("%4d", delta));
sb.append(extraTracingStatistics.get(i).getUnits());
sb.append("; ");
}
}
}
sb.append(indent);
sb.append(tracer.toString());
return sb.toString();
}
}
/** Stores a thread's Trace */
static final class ThreadTrace {
/** Events taking less than this number of milliseconds are not reported. */
int defaultSilenceThreshold; // non-final
/** The Events corresponding to each startEvent/stopEvent */
final ArrayList<Event> events = new ArrayList<Event>();
/** Tracers that have not had their .stop() called */
final HashSet<Tracer> outstandingEvents = new HashSet<Tracer>();
/** Map from type to Stat object */
final Map<String, Stat> stats = new HashMap<String, Stat>();
/**
* True if {@code outstandingEvents} has been cleared because we exceeded
* the max trace limit.
*/
boolean isOutstandingEventsTruncated = false;
/**
* True if {@code events} has been cleared because we exceeded the max
* trace limit.
*/
boolean isEventsTruncated = false;
/**
* Set to true if {@link Tracer#initCurrentThreadTrace()} was called by
* the current thread.
*/
boolean isInitialized = false;
/**
* Whether pretty printing is enabled for the trace.
*/
boolean prettyPrint = false;
/** Initialize the trace. */
void init() {
isInitialized = true;
}
/** Is initialized? */
boolean isInitialized() {
return isInitialized;
}
/**
* Called by the constructor {@link Tracer#Tracer(String, String)} to create
* a start event.
*/
void startEvent(Tracer t) {
events.add(new Event(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>typeToTimeMap != null) {
typeToTimeMap.incrementBy(t.type, elapsed);
}
if (stat.extraInfo != null && t.extraTracingValues != null) {
int overlapLength =
Math.min(stat.extraInfo.length, t.extraTracingValues.length);
for (int i = 0; i < overlapLength; i++) {
stat.extraInfo[i] += t.extraTracingValues[i];
AtomicTracerStatMap map =
extraTracingStatistics.get(i).getTracingStat();
if (map != null) {
map.incrementBy(t.type, t.extraTracingValues[i]);
}
}
}
if (elapsed < silenceThreshold) {
stat.silent++;
if (typeToSilentMap != null) {
typeToSilentMap.incrementBy(t.type, 1);
}
}
}
}
boolean isEmpty() {
return events.size() == 0 && outstandingEvents.size() == 0;
}
void truncateOutstandingEvents() {
isOutstandingEventsTruncated = true;
outstandingEvents.clear();
}
void truncateEvents() {
isEventsTruncated = true;
events.clear();
}
/** Produces the lovely Trace seen in the class comments */
// Nullness checker does not understand that prettyPrint => indent != null
@SuppressWarnings("nullness")
@Override public String toString() {
int numDigits = getMaxDigits();
StringBuilder sb = new StringBuilder();
long etime = -1;
LinkedList<String> indent = prettyPrint ? new LinkedList<String>() : null;
for (Event e : events) {
if (prettyPrint && !e.isStart && !indent.isEmpty()) {
indent.pop();
}
sb.append(" ");
if (prettyPrint) {
sb.append(e.toString(etime, Joiner.on("").join(indent), numDigits));
} else {
sb.append(e.toString(etime, "", 4));
}
etime = e.eventTime();
sb.append('\n');
if (prettyPrint && e.isStart) {
indent.push("| ");
}
}
if (outstandingEvents.size() != 0) {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
long now = clock.currentTimeMillis();
sb.append(" Unstopped timers:\n");
for (Tracer t : outstandingEvents) {
sb.append(" ").
append(t).
append(" (").
append(now - t.startTimeMs).
append(" ms, started at ").
append(formatTime(t.startTimeMs)).
append(")\n");
}
}
for (String key : stats.keySet()) {
Stat stat = stats.get(key);
if (stat.count > 1) {
sb.append(" TOTAL ").
append(key).
append(" ").
append(stat.count).
append(" (").
append(stat.clockTime).
append(" ms");
if (stat.extraInfo != null) {
for (int i = 0; i < stat.extraInfo.length; i++) {
sb.append("; ");
sb.append(stat.extraInfo[i]).
append(' ').
append(extraTracingStatistics.get(i).getUnits());
}
}
sb.append(")\n");
}
}
return sb.toString();
}
/**
* Gets the maximum number of digits that can appear in the tracer output
* in the gaps between tracers or the duration of a tracer. This is used
* by the pretty printing case so that all of the tracers are aligned.
*/
private int getMaxDigits() {
long etime = -1;
long max_time = 0;
for (Event e : events) {
if (etime != -1) {
long time = e.eventTime() - etime;
max_time = Math.max(max_time, time);
}
if (!e.isStart) {
long time = e.tracer.stopTimeMs - e.tracer.startTimeMs;
max_time = Math.max(max_time, time);
}
etime = e.eventTime();
}
// Minimum is 3 to preserve an indent even when max is small.
return Math.max(3, numDigits(max_time));
}
}
/** Holds the ThreadTrace for each thread. */
private static ThreadLocal<ThreadTrace> traces =
new ThreadLocal<ThreadTrace>();
/**
* Get the
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> class AtomicTracerStatMap {
private ConcurrentMap<String, Long> map =
new ConcurrentHashMap<String, Long>();
/**
* Atomically increment the specified field by the specified amount.
*
* @param key the name of the field
* @param delta the amount by which to increment the field
*/
// Nullness checker is not powerful enough to prove null-safety of
// this method
@SuppressWarnings("nullness")
void incrementBy(String key, long delta) {
// We use a compareAndSet strategy to update the map, which is much
// faster when there isn't too much contention. Look at a value, and
// conditionally update the map if the value hasn't changed.
// If it has changed, repeat.
Long oldValue = map.get(key);
if (oldValue == null) {
// Currently, the slot is empty
oldValue = map.putIfAbsent(key, delta);
if (oldValue == null) {
// The slot was still empty when we set it
return;
} else {
// Someone filled in the slot behind our back. oldValue has
// its current value
}
}
while (true) {
if (map.replace(key, oldValue, oldValue + delta)) {
break;
}
// Nullness checker doesn't understand that this cannot return null.
oldValue = map.get(key);
}
}
/**
* Returns a map of key:value pairs.
*/
Map<String, Long> getMap() {
return map;
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> a subtype of typeB */
static boolean isSubtype(ObjectType typeA, RecordType typeB) {
// typeA is a subtype of record type typeB iff:
// 1) typeA has all the properties declared in typeB.
// 2) And for each property of typeB,
// 2a) if the property of typeA is declared, it must be equal
// to the type of the property of typeB,
// 2b) otherwise, it must be a subtype of the property of typeB.
//
// To figure out why this is true, consider the following pseudo-code:
// /** @type {{a: (Object,null)}} */ var x;
// /** @type {{a: !Object}} */ var y;
// var z = {a: {}};
// x.a = null;
//
// y cannot be assigned to x, because line 4 would violate y's declared
// properties. But z can be assigned to x. Even though z and y are the
// same type, the properties of z are inferred--and so an assignment
// to the property of z would not violate any restrictions on it.
for (String property : typeB.properties.keySet()) {
if (!typeA.hasProperty(property)) {
return false;
}
JSType propA = typeA.getPropertyType(property);
JSType propB = typeB.getPropertyType(property);
if (!propA.isUnknownType() && !propB.isUnknownType()) {
if (typeA.isPropertyTypeDeclared(property)) {
if (!propA.isEquivalentTo(propB)) {
return false;
}
} else {
if (!propA.isSubtype(propB)) {
return false;
}
}
}
}
return true;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("{ ");
int i = 0;
for (String property : properties.keySet()) {
if (i > 0) {
sb.append(", ");
}
sb.append(property);
sb.append(" : ");
sb.append(properties.get(property).toString());
++i;
}
sb.append(" }");
return sb.toString();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>see NodeTraversal
* @see DataFlowAnalysis
*
*/
public class Scope implements StaticScope<JSType> {
private final Map<String, Var> vars = new LinkedHashMap<String, Var>();
private final Scope parent;
private final int depth;
private final Node rootNode;
/** The type of {@code this} in the current scope. */
private final ObjectType thisType;
/** Whether this is a bottom scope for the purposes of type inference. */
private final boolean isBottom;
private Var arguments;
/** Stores info about a variable */
public static class Var implements StaticSlot<JSType> {
/** name */
final String name;
/** Var node */
final Node nameNode;
/**
* The variable's type.
*/
private JSType type;
/**
* The variable's doc info.
*/
private final JSDocInfo info;
/**
* Whether the variable's type has been inferred or is declared. An inferred
* type may change over time (as more code is discovered), whereas a
* declared type is a static contract that must be matched.
*/
private final boolean typeInferred;
/** Input source */
final CompilerInput input;
/** Whether the variable is a define */
final boolean isDefine;
/**
* The index at which the var is declared. e..g if it's 0, it's the first
* declared variable in that scope
*/
final int index;
/** The enclosing scope */
final Scope scope;
/**
* Creates a variable.
*
* @param inferred whether its type is inferred (as opposed to declared)
*/
private Var(boolean inferred, String name, Node nameNode, JSType type,
Scope scope, int index, CompilerInput input, boolean isDefine,
JSDocInfo info) {
this.name = name;
this.nameNode = nameNode;
this.type = type;
this.scope = scope;
this.index = index;
this.input = input;
this.isDefine = isDefine;
this.info = info;
this.typeInferred = inferred;
}
/**
* Gets the name of the variable.
*/
public String getName() {
return name;
}
/**
* Gets the parent of the name node.
*/
public Node
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> getParentNode() {
return nameNode == null ? null : nameNode.getParent();
}
/**
* Whether this is a bleeding function (an anonymous named function
* that bleeds into the inner scope.
*/
public boolean isBleedingFunction() {
return NodeUtil.isFunctionExpression(getParentNode());
}
/**
* Gets the scope where this variable is declared.
*/
Scope getScope() {
return scope;
}
/**
* Returns whether this is a global variable.
*/
public boolean isGlobal() {
return scope.isGlobal();
}
/**
* Returns whether this is a local variable.
*/
public boolean isLocal() {
return scope.isLocal();
}
/**
* Returns whether this is defined in an extern file.
*/
boolean isExtern() {
return input == null || input.isExtern();
}
/**
* Returns {@code true} if the variable is declared as a constant,
* based on the value reported by {@code NodeUtil}.
*/
public boolean isConst() {
return nameNode != null && NodeUtil.isConstantName(nameNode);
}
/**
* Returns {@code true} if the variable is declared as a define.
* A variable is a define if it is annotaed by {@code @define}.
*/
public boolean isDefine() {
return isDefine;
}
public Node getInitialValue() {
Node parent = getParentNode();
int pType = parent.getType();
if (pType == Token.FUNCTION) {
return parent;
} else if (pType == Token.ASSIGN) {
return parent.getLastChild();
} else if (pType == Token.VAR) {
return nameNode.getFirstChild();
} else {
return null;
}
}
/**
* Gets this variable's type. To know whether this type has been inferred,
* see {@code #isInferred()}.
*/
public JSType getType() {
return type;
}
/**
* Returns the name node that produced this variable.
*/
public Node getNameNode() {
return nameNode;
}
/**
* Gets the JSDocInfo for the variable.
*/
public JSDocInfo getJSDocInfo() {
return info;
}
/**
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
* Sets this variable's type.
* @throws IllegalStateException if the variable's type is not inferred
*/
void setType(JSType type) {
Preconditions.checkState(isTypeInferred());
this.type = type;
}
/**
* Resolve this variable's type.
*/
void resolveType(ErrorReporter errorReporter) {
if (type != null) {
type = type.resolve(errorReporter, scope);
}
}
/**
* Returns whether this variable's type is inferred. To get the variable's
* type, see {@link #getType()}.
*/
public boolean isTypeInferred() {
return typeInferred;
}
public String getInputName() {
if (input == null)
return "<non-file>";
else
return input.getName();
}
public boolean isNoShadow() {
if (info != null && info.isNoShadow()) {
return true;
} else {
return false;
}
}
@Override public boolean equals(Object other) {
if (!(other instanceof Var)) {
return false;
}
Var otherVar = (Var) other;
return otherVar.nameNode == nameNode;
}
@Override public int hashCode() {
return nameNode.hashCode();
}
@Override
public String toString() {
return "Scope.Var " + name;
}
}
/**
* A special subclass of Var used to distinguish "arguments" in the current
* scope.
*/
// TODO(johnlenz): Include this the list of Vars for the scope.
public static class Arguments extends Var {
Arguments(Scope scope) {
super(
false, // no inferred
"arguments", // always arguments
null, // no declaration node
// TODO(johnlenz): provide the type of "Arguments".
null, // no type info
scope,
-1, // no variable index
null, // input,
false, // not a define
null // no jsdoc
);
}
@Override public boolean equals(Object other) {
if (!(other instanceof Arguments)) {
return false;
}
Arguments otherVar = (Arguments) other;
return otherVar.scope.getRootNode() == scope.getRootNode();
}
@Override public int hashCode() {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
result = result.getParent();
}
return result;
}
@Override
public StaticScope<JSType> getParentScope() {
return parent;
}
/**
* Gets the type of {@code this} in the current scope.
*/
public ObjectType getTypeOfThis() {
return thisType;
}
/**
* Declares a variable whose type is inferred.
*
* @param name name of the variable
* @param nameNode the NAME node declaring the variable
* @param type the variable's type
* @param input the input in which this variable is defined.
*/
Var declare(String name, Node nameNode, JSType type, CompilerInput input) {
return declare(name, nameNode, type, input, true);
}
/**
* Declares a variable.
*
* @param name name of the variable
* @param nameNode the NAME node declaring the variable
* @param type the variable's type
* @param input the input in which this variable is defined.
* @param inferred Whether this variable's type is inferred (as opposed
* to declared).
*/
Var declare(String name, Node nameNode,
JSType type, CompilerInput input, boolean inferred) {
Preconditions.checkState(name != null && name.length() > 0);
// Make sure that it's declared only once
Preconditions.checkState(vars.get(name) == null);
// native variables do not have a name node.
// TODO(user): make Var abstract and have NativeVar, NormalVar.
JSDocInfo info = NodeUtil.getInfoForNameNode(nameNode);
Var var = new Var(inferred, name, nameNode, type, this, vars.size(), input,
info != null && info.isDefine(), info);
vars.put(name, var);
return var;
}
/**
* Undeclares a variable, to be used when the compiler optimizes out
* a variable and removes it from the scope.
*/
void undeclare(Var var) {
Preconditions.checkState(var.scope == this);
Preconditions.checkState(vars.get(var.name) == var);
vars.remove(var.name);
}
public StaticSlot<JSType> getSlot(String name)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2008 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp.graph;
import java.util.Collection;
/**
* A minimal graph interface. Provided is add nodes to the graph, adjacency
* calculation between a SubGraph and a GraphNode, and adding node annotations.
*
* <p>For a more extensive interface, see {@link Graph}.
*
*
* @param <N> Value type that the graph node stores.
* @param <E> Value type that the graph edge stores.
* @see Graph
*/
public interface AdjacencyGraph<N, E> {
/** Gets an immutable list of all nodes. */
Collection<GraphNode<N, E>> getNodes();
/**
* Gets a node from the graph given a value. Values equality are compared
* using <code>Object.equals</code>.
*
* @param value The node's value.
* @return The corresponding node in the graph, null if there value has no
* corresponding node.
*/
GraphNode<N, E> getNode(N value);
/** Returns an empty SubGraph for this Graph. */
SubGraph<N, E> newSubGraph();
/** Makes each node's annotation null. */
void clearNodeAnnotations();
/**
* Returns a weight for the given value to be used in ordering nodes, e.g.
* in {@link GraphColoring}.
*/
int getWeight(N value);
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> All type is the greatest type (top) and is never a subtype of
* another except itself or the Unknown type or a named alias.
* @return {@code this.isEquivalentTo(that)}
*/
@Override
public boolean isSubtype(JSType that) {
return JSType.isSubtype(this, that);
}
@Override
public boolean isAllType() {
return true;
}
@Override
public boolean matchesStringContext() {
// Be lenient.
return true;
}
@Override
public boolean matchesObjectContext() {
// Be lenient.
return true;
}
@Override
public boolean canBeCalled() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
return UNKNOWN;
}
@Override
public String toString() {
return "*";
}
@Override
public String getDisplayName() {
return "<Any Type>";
}
@Override
public boolean hasDisplayName() {
return true;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseAllType();
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
JSType resolveInternal(ErrorReporter t, StaticScope<JSType> scope) {
return this;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> of tweaks based on compiler options. */
private void applyCompilerDefaultValueOverrides(
Map<String, TweakInfo> tweakInfos) {
for (Entry<String, Node> entry : compilerDefaultValueOverrides.entrySet()) {
String tweakId = entry.getKey();
TweakInfo tweakInfo = tweakInfos.get(tweakId);
if (tweakInfo == null) {
compiler.report(JSError.make(UNKNOWN_TWEAK_WARNING, tweakId));
} else {
TweakFunction registerFunc = tweakInfo.registerCall.tweakFunc;
Node value = entry.getValue();
if (!registerFunc.isValidNodeType(value.getType())) {
compiler.report(JSError.make(INVALID_TWEAK_DEFAULT_VALUE_WARNING,
tweakId, registerFunc.getName(),
registerFunc.getExpectedTypeName()));
} else {
tweakInfo.defaultValueNode = value;
}
}
}
}
/**
* Finds all calls to goog.tweak functions and emits warnings/errors if any
* of the calls have issues.
* @return A map of {@link TweakInfo} structures, keyed by tweak ID.
*/
private CollectTweaksResult collectTweaks(Node root) {
CollectTweaks pass = new CollectTweaks();
NodeTraversal.traverse(compiler, root, pass);
Map<String, TweakInfo> tweakInfos = pass.allTweaks;
for (TweakInfo tweakInfo: tweakInfos.values()) {
tweakInfo.emitAllWarnings();
}
return new CollectTweaksResult(tweakInfos, pass.getOverridesCalls);
}
private final static class CollectTweaksResult {
final Map<String, TweakInfo> tweakInfos;
final List<TweakFunctionCall> getOverridesCalls;
CollectTweaksResult(Map<String, TweakInfo> tweakInfos,
List<TweakFunctionCall> getOverridesCalls) {
this.tweakInfos = tweakInfos;
this.getOverridesCalls = getOverridesCalls;
}
}
/**
* Processes all calls to goog.tweak functions.
*/
private final class CollectTweaks extends AbstractPostOrderCallback {
final Map<String, TweakInfo> allTweaks = Maps.newHashMap();
final List<TweakFunctionCall
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> number, and date.
*/
public final String getImplementationVersion()
{
// XXX Probably it would be better to embed this directly into source
// with special build preprocessing but that would require some ant
// tweaking and then replacing token in resource files was simpler
if (implementationVersion == null) {
implementationVersion
= ScriptRuntime.getMessage0("implementation.version");
}
return implementationVersion;
}
/**
* Get the current error reporter.
*
* @see com.google.javascript.rhino.ErrorReporter
*/
public final ErrorReporter getErrorReporter()
{
return errorReporter;
}
/**
* Change the current error reporter.
*
* @return the previous error reporter
* @see com.google.javascript.rhino.ErrorReporter
*/
public final ErrorReporter setErrorReporter(ErrorReporter reporter)
{
if (sealed) onSealedMutation();
if (reporter == null) throw new IllegalArgumentException();
ErrorReporter old = getErrorReporter();
if (reporter == old) {
return old;
}
Object listeners = propertyListeners;
if (listeners != null) {
firePropertyChangeImpl(listeners, errorReporterProperty,
old, reporter);
}
this.errorReporter = reporter;
return old;
}
/**
* Get the current locale. Returns the default locale if none has
* been set.
*
* @see java.util.Locale
*/
public final Locale getLocale()
{
if (locale == null)
locale = Locale.getDefault();
return locale;
}
/**
* Set the current locale.
*
* @see java.util.Locale
*/
public final Locale setLocale(Locale loc)
{
if (sealed) onSealedMutation();
Locale result = locale;
locale = loc;
return result;
}
/**
* Register an object to receive notifications when a bound property
* has changed
* @see java.beans.PropertyChangeEvent
* @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
* @param l the listener
*/
public final void addPropertyChangeListener(PropertyChangeListener l)
{
if (sealed) onSealedMutation();
propertyListeners = Kit.addListener(propertyListeners, l);
}
/**
* Remove an object from the list of objects
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> registered to receive
* notification of changes to a bounded property
* @see java.beans.PropertyChangeEvent
* @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
* @param l the listener
*/
public final void removePropertyChangeListener(PropertyChangeListener l)
{
if (sealed) onSealedMutation();
propertyListeners = Kit.removeListener(propertyListeners, l);
}
/**
* Notify any registered listeners that a bounded property has changed
* @see #addPropertyChangeListener(java.beans.PropertyChangeListener)
* @see #removePropertyChangeListener(java.beans.PropertyChangeListener)
* @see java.beans.PropertyChangeListener
* @see java.beans.PropertyChangeEvent
* @param property the bound property
* @param oldValue the old value
* @param newValue the new value
*/
final void firePropertyChange(String property, Object oldValue,
Object newValue)
{
Object listeners = propertyListeners;
if (listeners != null) {
firePropertyChangeImpl(listeners, property, oldValue, newValue);
}
}
private void firePropertyChangeImpl(Object listeners, String property,
Object oldValue, Object newValue)
{
for (int i = 0; ; ++i) {
Object l = Kit.getListener(listeners, i);
if (l == null)
break;
if (l instanceof PropertyChangeListener) {
PropertyChangeListener pcl = (PropertyChangeListener)l;
pcl.propertyChange(new PropertyChangeEvent(
this, property, oldValue, newValue));
}
}
}
/**
* Report a warning using the error reporter for the current thread.
*
* @param message the warning message to report
* @param sourceName a string describing the source, such as a filename
* @param lineno the starting line number
* @param lineSource the text of the line (may be null)
* @param lineOffset the offset into lineSource where problem was detected
* @see com.google.javascript.rhino.ErrorReporter
*/
public static void reportWarning(String message, String sourceName,
int lineno, String lineSource,
int lineOffset)
{
Context cx = Context.getContext();
cx.getErrorReporter().warning(message, sourceName, lineno,
lineSource, lineOffset);
}
/**
* Report
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>p>
* @param key the key used to index the value
* @param value the value to save
*/
public final void putThreadLocal(Object key, Object value)
{
if (sealed) onSealedMutation();
if (hashtable == null)
hashtable = new Hashtable<Object, Object>();
hashtable.put(key, value);
}
/**
* Remove values from thread-local storage.
* @param key the key for the entry to remove.
* @since 1.5 release 2
*/
public final void removeThreadLocal(Object key)
{
if (sealed) onSealedMutation();
if (hashtable == null)
return;
hashtable.remove(key);
}
/**
* @deprecated
* @see #FEATURE_DYNAMIC_SCOPE
* @see #hasFeature(int)
*/
@Deprecated
public final boolean hasCompileFunctionsWithDynamicScope()
{
return compileFunctionsWithDynamicScopeFlag;
}
/**
* @deprecated
* @see #FEATURE_DYNAMIC_SCOPE
* @see #hasFeature(int)
*/
@Deprecated
public final void setCompileFunctionsWithDynamicScope(boolean flag)
{
if (sealed) onSealedMutation();
compileFunctionsWithDynamicScopeFlag = flag;
}
/**
* Return the debugger context data associated with current context.
* @return the debugger data, or null if debugger is not attached
*/
public final Object getDebuggerContextData()
{
return debuggerData;
}
/**
* Implementation of {@link Context#hasFeature(int featureIndex)}.
* This can be used to customize {@link Context} without introducing
* additional subclasses.
*/
protected boolean hasFeature(int featureIndex)
{
int version;
switch (featureIndex) {
case Context.FEATURE_NON_ECMA_GET_YEAR:
/*
* During the great date rewrite of 1.3, we tried to track the
* evolving ECMA standard, which then had a definition of
* getYear which always subtracted 1900. Which we
* implemented, not realizing that it was incompatible with
* the old behavior... now, rather than thrash the behavior
* yet again, we've decided to leave it with the - 1
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>");
}
return cx;
}
final boolean isVersionECMA1()
{
return version == VERSION_DEFAULT || version >= VERSION_1_3;
}
static String getSourcePositionFromStack(int[] linep)
{
Context cx = getCurrentContext();
if (cx == null)
return null;
/**
* A bit of a hack, but the only way to get filename and line
* number from an enclosing frame.
*/
CharArrayWriter writer = new CharArrayWriter();
RuntimeException re = new RuntimeException();
re.printStackTrace(new PrintWriter(writer));
String s = writer.toString();
int open = -1;
int close = -1;
int colon = -1;
for (int i=0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == ':')
colon = i;
else if (c == '(')
open = i;
else if (c == ')')
close = i;
else if (c == '\n' && open != -1 && close != -1 && colon != -1 &&
open < colon && colon < close)
{
String fileStr = s.substring(open + 1, colon);
if (!fileStr.endsWith(".java")) {
String lineStr = s.substring(colon + 1, close);
try {
linep[0] = Integer.parseInt(lineStr);
if (linep[0] < 0) {
linep[0] = 0;
}
return fileStr;
}
catch (NumberFormatException e) {
// fall through
}
}
open = close = colon = -1;
}
}
return null;
}
public final boolean isGeneratingDebugChanged()
{
return generatingDebugChanged;
}
/**
* Add a name to the list of names forcing the creation of real
* activation objects for functions.
*
* @param name the name of the object to add to the list
*/
public void addActivationName(String name)
{
if (sealed) onSealedMutation();
if (activationNames == null)
activationNames = new Hashtable<Object, Object>(5);
activationNames.put(name, name);
}
/**
*
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
"JSC_RESOLVED_TAG_EMPTY",
"Could not resolve type in {0} tag of {1}");
static final DiagnosticType IMPLEMENTS_WITHOUT_CONSTRUCTOR =
DiagnosticType.warning(
"JSC_IMPLEMENTS_WITHOUT_CONSTRUCTOR",
"@implements used without @constructor or @interface for {0}");
static final DiagnosticType VAR_ARGS_MUST_BE_LAST = DiagnosticType.warning(
"JSC_VAR_ARGS_MUST_BE_LAST",
"variable length argument must be last");
static final DiagnosticType OPTIONAL_ARG_AT_END = DiagnosticType.warning(
"JSC_OPTIONAL_ARG_AT_END",
"optional arguments must be at the end");
static final DiagnosticType INEXISTANT_PARAM = DiagnosticType.warning(
"JSC_INEXISTANT_PARAM",
"parameter {0} does not appear in {1}''s parameter list");
static final DiagnosticType TYPE_REDEFINITION = DiagnosticType.warning(
"JSC_TYPE_REDEFINITION",
"attempted re-definition of type {0}\n"
+ "found : {1}\n"
+ "expected: {2}");
static final DiagnosticType TEMPLATE_TYPE_DUPLICATED = DiagnosticType.error(
"JSC_TEMPLATE_TYPE_DUPLICATED",
"Only one parameter type must be the template type");
static final DiagnosticType TEMPLATE_TYPE_EXPECTED = DiagnosticType.error(
"JSC_TEMPLATE_TYPE_EXPECTED",
"The template type must be a parameter type");
static final DiagnosticType THIS_TYPE_NON_OBJECT =
DiagnosticType.warning(
"JSC_THIS_TYPE_NON_OBJECT",
"@this type of a function must be an object\n" +
"Actual type: {0}");
private class ExtendedTypeValidator implements Predicate<JSType> {
@Override
public boolean apply(JSType type) {
ObjectType objectType = ObjectType.cast(type);
if (objectType == null) {
reportWarning(EXTENDS_NON_OBJECT, fnName, type.toString());
} else if (
objectType.isEmptyType() ||
(objectType.isUnknownType() &&
// If this has a supertype that hasn't been resolved yet,
// then we can assume this type will be
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> ok once the super
// type resolves.
(objectType.getImplicitPrototype() == null ||
objectType.getImplicitPrototype().isResolved()))) {
reportWarning(RESOLVED_TAG_EMPTY, "@extends", fnName);
} else {
return true;
}
return false;
}
}
private class ImplementedTypeValidator implements Predicate<JSType> {
@Override
public boolean apply(JSType type) {
ObjectType objectType = ObjectType.cast(type);
if (objectType == null) {
reportError(BAD_IMPLEMENTED_TYPE, fnName);
} else if (
objectType.isEmptyType() ||
(objectType.isUnknownType() &&
// If this has a supertype that hasn't been resolved yet,
// then we can assume this type will be ok once the super
// type resolves.
(objectType.getImplicitPrototype() == null ||
objectType.getImplicitPrototype().isResolved()))) {
reportWarning(RESOLVED_TAG_EMPTY, "@implements", fnName);
} else {
return true;
}
return false;
}
}
private class ThisTypeValidator implements Predicate<JSType> {
@Override
public boolean apply(JSType type) {
// TODO(user): Doing an instanceof check here is too
// restrictive as (Date,Error) is, for instance, an object type
// even though its implementation is a UnionType. Would need to
// create interfaces JSType, ObjectType, FunctionType etc and have
// separate implementation instead of the class hierarchy, so that
// union types can also be object types, etc.
if (!type.restrictByNotNullOrUndefined().isSubtype(
typeRegistry.getNativeType(OBJECT_TYPE))) {
reportWarning(THIS_TYPE_NON_OBJECT, type.toString());
return false;
}
return true;
}
}
/**
* @param fnName The function name.
* @param compiler The compiler.
* @param errorRoot The node to associate with any warning generated by
* this builder.
* @param sourceName A source name for associating any warnings that
* we have to emit.
* @param scope The syntactic scope.
*/
FunctionTypeBuilder(String fnName, AbstractCompiler compiler,
Node errorRoot, String sourceName, Scope
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> method might right its var_args as individual
// arguments.
if (currentParam.getNext() != null && newParam.isVarArgs()) {
newParam.setVarArgs(false);
newParam.setOptionalArg(true);
}
} else {
warnedAboutArgList |= addParameter(
paramBuilder,
typeRegistry.getNativeType(UNKNOWN_TYPE),
warnedAboutArgList,
codingConvention.isOptionalParameter(currentParam) ||
oldParamsListHitOptArgs,
codingConvention.isVarArgsParameter(currentParam));
}
}
parametersNode = paramBuilder.build();
}
return this;
}
/**
* Infer the return type from JSDocInfo.
*/
FunctionTypeBuilder inferReturnType(@Nullable JSDocInfo info) {
if (info != null && info.hasReturnType()) {
returnType = info.getReturnType().evaluate(scope, typeRegistry);
returnTypeInferred = false;
}
if (templateTypeName != null &&
returnType != null &&
returnType.restrictByNotNullOrUndefined().isTemplateType()) {
reportError(TEMPLATE_TYPE_EXPECTED, fnName);
}
return this;
}
/**
* If we haven't found a return value yet, try to look at the "return"
* statements in the function.
*/
FunctionTypeBuilder inferReturnStatementsAsLastResort(
@Nullable Node functionBlock) {
if (functionBlock == null || compiler.getInput(sourceName).isExtern()) {
return this;
}
Preconditions.checkArgument(functionBlock.getType() == Token.BLOCK);
if (returnType == null) {
boolean hasNonEmptyReturns = false;
List<Node> worklist = Lists.newArrayList(functionBlock);
while (!worklist.isEmpty()) {
Node current = worklist.remove(worklist.size() - 1);
int cType = current.getType();
if (cType == Token.RETURN && current.getFirstChild() != null) {
hasNonEmptyReturns = true;
break;
} else if (NodeUtil.isStatementBlock(current) ||
NodeUtil.isControlStructure(current)) {
for (Node child = current.getFirstChild();
child != null; child = child.getNext()) {
worklist.add(child);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
}
}
}
if (!hasNonEmptyReturns) {
returnType = typeRegistry.getNativeType(VOID_TYPE);
returnTypeInferred = true;
}
}
return this;
}
/**
* Infer the role of the function (whether it's a constructor or interface)
* and what it inherits from in JSDocInfo.
*/
FunctionTypeBuilder inferInheritance(@Nullable JSDocInfo info) {
if (info != null) {
isConstructor = info.isConstructor();
isInterface = info.isInterface();
// base type
if (info.hasBaseType()) {
if (isConstructor || isInterface) {
JSType maybeBaseType =
info.getBaseType().evaluate(scope, typeRegistry);
if (maybeBaseType != null &&
maybeBaseType.setValidator(new ExtendedTypeValidator())) {
baseType = (ObjectType) maybeBaseType;
}
} else {
reportWarning(EXTENDS_WITHOUT_TYPEDEF, fnName);
}
}
// implemented interfaces
if (isConstructor || isInterface) {
implementedInterfaces = Lists.newArrayList();
for (JSTypeExpression t : info.getImplementedInterfaces()) {
JSType maybeInterType = t.evaluate(scope, typeRegistry);
if (maybeInterType != null &&
maybeInterType.setValidator(new ImplementedTypeValidator())) {
implementedInterfaces.add((ObjectType) maybeInterType);
}
}
if (baseType != null) {
JSType maybeFunctionType = baseType.getConstructor();
if (maybeFunctionType instanceof FunctionType) {
FunctionType functionType = baseType.getConstructor();
Iterables.addAll(
implementedInterfaces,
functionType.getImplementedInterfaces());
}
}
} else if (info.getImplementedInterfaceCount() > 0) {
reportWarning(IMPLEMENTS_WITHOUT_CONSTRUCTOR, fnName);
}
}
return this;
}
/**
* Infers the type of {@code this}.
* @param type The type of this.
*/
FunctionTypeBuilder inferThisType(JSDocInfo info, JSType type) {
// Look at the @this annotation first.
inferThisType(info, (Node) null);
if (thisType == null) {
ObjectType objType = ObjectType.cast(type);
if (
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>objType != null && (info == null || !info.hasType())) {
thisType = objType;
}
}
return this;
}
/**
* Infers the type of {@code this}.
* @param info The JSDocInfo for this function.
* @param owner The node for the object whose prototype "owns" this function.
* For example, {@code A} in the expression {@code A.prototype.foo}. May
* be null to indicate that this is not a prototype property.
*/
FunctionTypeBuilder inferThisType(JSDocInfo info,
@Nullable Node owner) {
ObjectType maybeThisType = null;
if (info != null && info.hasThisType()) {
maybeThisType = ObjectType.cast(
info.getThisType().evaluate(scope, typeRegistry));
}
if (maybeThisType != null) {
thisType = maybeThisType;
thisType.setValidator(new ThisTypeValidator());
} else if (owner != null &&
(info == null || !info.hasType())) {
// If the function is of the form:
// x.prototype.y = function() {}
// then we can assume "x" is the @this type. On the other hand,
// if it's of the form:
// /** @type {Function} */ x.prototype.y;
// then we should not give it a @this type.
String ownerTypeName = owner.getQualifiedName();
Var ownerVar = scope.getVar(ownerTypeName);
JSType ownerType = ownerVar == null ? null : ownerVar.getType();
FunctionType ownerFnType = ownerType instanceof FunctionType ?
(FunctionType) ownerType : null;
ObjectType instType =
ownerFnType == null || ownerFnType.isOrdinaryFunction() ?
null : ownerFnType.getInstanceType();
if (instType != null) {
thisType = instType;
}
}
return this;
}
/**
* Infer the parameter types from the doc info alone.
*/
FunctionTypeBuilder inferParameterTypes(JSDocInfo info) {
// Create a fake args parent.
Node lp = new Node(Token.LP);
for (String name : info.getParameterNames()) {
lp.addChildToBack(Node.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>newString(Token.NAME, name));
}
return inferParameterTypes(lp, info);
}
/**
* Infer the parameter types from the list of argument names and
* the doc info.
*/
FunctionTypeBuilder inferParameterTypes(@Nullable Node argsParent,
@Nullable JSDocInfo info) {
if (argsParent == null) {
if (info == null) {
return this;
} else {
return inferParameterTypes(info);
}
}
// arguments
Node oldParameterType = null;
if (parametersNode != null) {
oldParameterType = parametersNode.getFirstChild();
}
FunctionParamBuilder builder = new FunctionParamBuilder(typeRegistry);
boolean warnedAboutArgList = false;
Set<String> allJsDocParams = (info == null) ?
Sets.<String>newHashSet() :
Sets.newHashSet(info.getParameterNames());
boolean foundTemplateType = false;
for (Node arg : argsParent.children()) {
String argumentName = arg.getString();
allJsDocParams.remove(argumentName);
// type from JSDocInfo
JSType parameterType = null;
boolean isOptionalParam = isOptionalParameter(arg, info);
boolean isVarArgs = isVarArgsParameter(arg, info);
if (info != null && info.hasParameterType(argumentName)) {
parameterType =
info.getParameterType(argumentName).evaluate(scope, typeRegistry);
} else if (oldParameterType != null &&
oldParameterType.getJSType() != null) {
parameterType = oldParameterType.getJSType();
isOptionalParam = oldParameterType.isOptionalArg();
isVarArgs = oldParameterType.isVarArgs();
} else {
parameterType = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
if (templateTypeName != null &&
parameterType.restrictByNotNullOrUndefined().isTemplateType()) {
if (foundTemplateType) {
reportError(TEMPLATE_TYPE_DUPLICATED, fnName);
}
foundTemplateType = true;
}
warnedAboutArgList |= addParameter(
builder, parameterType, warnedAboutArgList,
isOptionalParam,
isVarArgs);
if (oldParameterType != null) {
oldParameterType = oldParameterType.getNext();
}
}
if
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> (templateTypeName != null && !foundTemplateType) {
reportError(TEMPLATE_TYPE_EXPECTED, fnName);
}
for (String inexistentName : allJsDocParams) {
reportWarning(INEXISTANT_PARAM, inexistentName, fnName);
}
parametersNode = builder.build();
return this;
}
/**
* @return Whether the given param is an optional param.
*/
private boolean isOptionalParameter(
Node param, @Nullable JSDocInfo info) {
if (codingConvention.isOptionalParameter(param)) {
return true;
}
String paramName = param.getString();
return info != null && info.hasParameterType(paramName) &&
info.getParameterType(paramName).isOptionalArg();
}
/**
* Determine whether this is a var args parameter.
* @return Whether the given param is a var args param.
*/
private boolean isVarArgsParameter(
Node param, @Nullable JSDocInfo info) {
if (codingConvention.isVarArgsParameter(param)) {
return true;
}
String paramName = param.getString();
return info != null && info.hasParameterType(paramName) &&
info.getParameterType(paramName).isVarArgs();
}
/**
* Infer the template type from the doc info.
*/
FunctionTypeBuilder inferTemplateTypeName(@Nullable JSDocInfo info) {
if (info != null) {
templateTypeName = info.getTemplateTypeName();
typeRegistry.setTemplateTypeName(templateTypeName);
}
return this;
}
/**
* Add a parameter to the param list.
* @param builder A builder.
* @param paramType The parameter type.
* @param warnedAboutArgList Whether we've already warned about arg ordering
* issues (like if optional args appeared before required ones).
* @param isOptional Is this an optional parameter?
* @param isVarArgs Is this a var args parameter?
* @return Whether a warning was emitted.
*/
private boolean addParameter(FunctionParamBuilder builder,
JSType paramType, boolean warnedAboutArgList,
boolean isOptional, boolean isVarArgs) {
boolean emittedWarning = false;
if (isOptional) {
// Remembering that an optional parameter has been encountered
//
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
return fnType;
}
private void maybeSetBaseType(FunctionType fnType) {
if (baseType != null) {
fnType.setPrototypeBasedOn(baseType);
}
}
/**
* Returns a constructor function either by returning it from the
* registry if it exists or creating and registering a new type. If
* there is already a type, then warn if the existing type is
* different than the one we are creating, though still return the
* existing function if possible. The primary purpose of this is
* that registering a constructor will fail for all built-in types
* that are initialized in {@link JSTypeRegistry}. We a) want to
* make sure that the type information specified in the externs file
* matches what is in the registry and b) annotate the externs with
* the {@link JSType} from the registry so that there are not two
* separate JSType objects for one type.
*/
private FunctionType getOrCreateConstructor() {
FunctionType fnType = typeRegistry.createConstructorType(
fnName, sourceNode, parametersNode, returnType);
JSType existingType = typeRegistry.getType(fnName);
if (existingType != null) {
boolean isInstanceObject = existingType instanceof InstanceObjectType;
if (isInstanceObject || fnName.equals("Function")) {
FunctionType existingFn =
isInstanceObject ?
((InstanceObjectType) existingType).getConstructor() :
typeRegistry.getNativeFunctionType(FUNCTION_FUNCTION_TYPE);
if (existingFn.getSource() == null) {
existingFn.setSource(sourceNode);
}
if (!existingFn.hasEqualCallType(fnType)) {
reportWarning(TYPE_REDEFINITION, fnName,
fnType.toString(), existingFn.toString());
}
return existingFn;
} else {
// We fall through and return the created type, even though it will fail
// to register. We have no choice as we have to return a function. We
// issue an error elsewhere though, so the user should fix it.
}
}
maybeSetBaseType(fnType);
if (getScopeDeclaredIn().isGlobal() && !fnName.isEmpty()) {
typeRegistry.declareType(fnName, fnType.getInstanceType());
}
return fnType;
}
private void
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> reportWarning(DiagnosticType warning, String ... args) {
compiler.report(JSError.make(sourceName, errorRoot, warning, args));
}
private void reportError(DiagnosticType error, String ... args) {
compiler.report(JSError.make(sourceName, errorRoot, error, args));
}
/**
* Determines whether the given jsdoc info declares a function type.
*/
static boolean isFunctionTypeDeclaration(JSDocInfo info) {
return info.getParameterCount() > 0 ||
info.hasReturnType() ||
info.hasThisType() ||
info.isConstructor() ||
info.isInterface();
}
/**
* The scope that we should declare this function in, if it needs
* to be declared in a scope. Notice that TypedScopeCreator takes
* care of most scope-declaring.
*/
private Scope getScopeDeclaredIn() {
int dotIndex = fnName.indexOf(".");
if (dotIndex != -1) {
String rootVarName = fnName.substring(0, dotIndex);
Var rootVar = scope.getVar(rootVarName);
if (rootVar != null) {
return rootVar.getScope();
}
}
return scope;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
reportBadModuleReference(name, ref);
}
}
}
}
}
private void reportBadModuleReference(Name name, Ref ref) {
compiler.report(
JSError.make(ref.sourceName, ref.node, STRICT_MODULE_DEP_QNAME,
ref.module.getName(), name.declaration.module.getName(),
name.fullName()));
}
private void reportRefToUndefinedName(Name name, Ref ref) {
// grab the highest undefined ancestor to output in the warning message.
while (name.parent != null &&
name.parent.globalSets + name.parent.localSets == 0) {
name = name.parent;
}
// If this is an annotated EXPR-GET, don't do anything.
Node parent = ref.node.getParent();
if (parent.getType() == Token.EXPR_RESULT) {
JSDocInfo info = ref.node.getJSDocInfo();
if (info != null && info.hasTypedefType()) {
return;
}
}
compiler.report(
JSError.make(ref.sourceName, ref.node, level, UNDEFINED_NAME_WARNING,
name.fullName()));
}
/**
* Checks whether the given name is a property, and whether that property
* must be initialized with its full qualified name.
*/
private static boolean propertyMustBeInitializedByFullName(Name name) {
// If an object literal in the global namespace is never aliased,
// then all of its properties must be defined using its full qualified
// name. This implies that its properties must all be in the global
// namespace as well.
//
// The same is not true for FUNCTION and OTHER types, because their
// implicit prototypes have properties that are not captured by the global
// namespace.
return name.parent != null && name.parent.aliasingGets == 0 &&
name.parent.type == Name.Type.OBJECTLIT;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2004 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.rhino.Node;
import com.google.javascript.rhino.Token;
import junit.framework.TestCase;
public class CodePrinterTest extends TestCase {
static Node parse(String js) {
return parse(js, false);
}
static Node parse(String js, boolean checkTypes) {
Compiler compiler = new Compiler();
CompilerOptions options = new CompilerOptions();
// Allow getters and setters.
options.setLanguageIn(LanguageMode.ECMASCRIPT5);
compiler.initOptions(options);
Node n = compiler.parseTestCode(js);
if (checkTypes) {
DefaultPassConfig passConfig = new DefaultPassConfig(null);
CompilerPass typeResolver = passConfig.resolveTypes.create(compiler);
Node externs = new Node(Token.SCRIPT);
Node externAndJsRoot = new Node(Token.BLOCK, externs, n);
externAndJsRoot.setIsSyntheticBlock(true);
typeResolver.process(externs, n);
CompilerPass inferTypes = passConfig.inferTypes.create(compiler);
inferTypes.process(externs, n);
}
checkUnexpectedErrorsOrWarnings(compiler, 0);
return n;
}
private static void checkUnexpectedErrorsOrWarnings(
Compiler compiler, int expected) {
int actual = compiler.getErrors().length + compiler.getWarnings().length;
if (actual != expected) {
String msg = "";
for (JSError err : compiler.get
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Errors()) {
msg += "Error:" + err.toString() + "\n";
}
for (JSError err : compiler.getWarnings()) {
msg += "Warning:" + err.toString() + "\n";
}
assertEquals("Unexpected warnings or errors.\n " + msg, expected, actual);
}
}
String parsePrint(String js, boolean prettyprint, int lineThreshold) {
return new CodePrinter.Builder(parse(js)).setPrettyPrint(prettyprint)
.setLineLengthThreshold(lineThreshold).build();
}
String parsePrint(String js, boolean prettyprint, boolean lineBreak,
int lineThreshold) {
return new CodePrinter.Builder(parse(js)).setPrettyPrint(prettyprint)
.setLineLengthThreshold(lineThreshold).setLineBreak(lineBreak).build();
}
String parsePrint(String js, boolean prettyprint, boolean lineBreak,
int lineThreshold, boolean outputTypes) {
return new CodePrinter.Builder(parse(js, true)).setPrettyPrint(prettyprint)
.setOutputTypes(outputTypes)
.setLineLengthThreshold(lineThreshold).setLineBreak(lineBreak)
.build();
}
String parsePrint(String js, boolean prettyprint, boolean lineBreak,
int lineThreshold, boolean outputTypes,
boolean tagAsStrict) {
return new CodePrinter.Builder(parse(js, true)).setPrettyPrint(prettyprint)
.setOutputTypes(outputTypes)
.setLineLengthThreshold(lineThreshold).setLineBreak(lineBreak)
.setTagAsStrict(tagAsStrict)
.build();
}
String printNode(Node n) {
return new CodePrinter.Builder(n).setLineLengthThreshold(
CodePrinter.DEFAULT_LINE_LENGTH_THRESHOLD).build();
}
void assertPrintNode(String expectedJs, Node ast) {
assertEquals(expectedJs, printNode(ast));
}
public void testPrint() {
assertPrint("10 + a + b", "10+a+b");
assertPrint("10 + (30*50)", "10+30*50");
assertPrint("with(x) { x + 3; }", "with(x)x+3");
assertPrint("\"aa'a\"", "\"aa'a
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
Kit.codeBug();
}
return null;
}
private static class NumberNode extends Node {
private static final long serialVersionUID = 1L;
NumberNode(double number) {
super(Token.NUMBER);
this.number = number;
}
public NumberNode(double number, int lineno, int charno) {
super(Token.NUMBER, lineno, charno);
this.number = number;
}
@Override
public double getDouble() {
return this.number;
}
@Override
public void setDouble(double d) {
this.number = d;
}
@Override
boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
return (super.isEquivalentTo(node, compareJsType, recurse)
&& getDouble() == ((NumberNode) node).getDouble());
}
private double number;
}
private static class StringNode extends Node {
private static final long serialVersionUID = 1L;
StringNode(int type, String str) {
super(type);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
StringNode(int type, String str, int lineno, int charno) {
super(type, lineno, charno);
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
/**
* returns the string content.
* @return non null.
*/
@Override
public String getString() {
return this.str;
}
/**
* sets the string content.
* @param str the new value. Non null.
*/
@Override
public void setString(String str) {
if (null == str) {
throw new IllegalArgumentException("StringNode: str is null");
}
this.str = str;
}
@Override
boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
return (super.isEquivalentTo(node, compareJsType, recurse)
&& this.str.equals(((StringNode) node).str));
}
/**
* If the property is not defined, this was not a quoted key. The
* QUOTED_PROP int property
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
public Node(int nodeType, Node left, Node right, int lineno, int charno) {
this(nodeType, left, right);
sourcePosition = mergeLineCharNo(lineno, charno);
}
public Node(int nodeType, Node left, Node mid, Node right,
int lineno, int charno) {
this(nodeType, left, mid, right);
sourcePosition = mergeLineCharNo(lineno, charno);
}
public Node(int nodeType, Node left, Node mid, Node mid2, Node right,
int lineno, int charno) {
this(nodeType, left, mid, mid2, right);
sourcePosition = mergeLineCharNo(lineno, charno);
}
public Node(int nodeType, Node[] children, int lineno, int charno) {
this(nodeType, children);
sourcePosition = mergeLineCharNo(lineno, charno);
}
public Node(int nodeType, Node[] children) {
this.type = nodeType;
parent = null;
if (children.length != 0) {
this.first = children[0];
this.last = children[children.length - 1];
for (int i = 1; i < children.length; i++) {
if (null != children[i - 1].next) {
// fail early on loops. implies same node in array twice
throw new IllegalArgumentException("duplicate child");
}
children[i - 1].next = children[i];
Preconditions.checkArgument(children[i - 1].parent == null);
children[i - 1].parent = this;
}
Preconditions.checkArgument(children[children.length - 1].parent == null);
children[children.length - 1].parent = this;
if (null != this.last.next) {
// fail early on loops. implies same node in array twice
throw new IllegalArgumentException("duplicate child");
}
}
}
public static Node newNumber(double number) {
return new NumberNode(number);
}
public static Node newNumber(double number, int lineno, int charno) {
return new NumberNode(number, lineno, charno);
}
public static Node newString(String str) {
return new StringNode(Token.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>PropsFrom(Node other) {
Preconditions.checkState(this.propListHead == null,
"Node has existing properties.");
this.propListHead = other.propListHead;
return this;
}
public void removeProp(int propType) {
PropListItem result = removeProp(propListHead, propType);
if (result != propListHead) {
propListHead = result;
}
}
/**
* @param item The item to inspect
* @param propType The property to look for
* @return The replacement list if the property was removed, or
* 'item' otherwise.
*/
private PropListItem removeProp(PropListItem item, int propType) {
if (item == null) {
return null;
} else if (item.type == propType) {
return item.next;
} else {
PropListItem result = removeProp(item.next, propType);
if (result != item.next) {
return new PropListItem(
item.type, item.intValue, item.objectValue, result);
} else {
return item;
}
}
}
public Object getProp(int propType) {
PropListItem item = lookupProperty(propType);
if (item == null) {
return null;
}
return item.objectValue;
}
public boolean getBooleanProp(int propType) {
return getIntProp(propType) != 0;
}
/**
* Returns the integer value for the property, or 0 if the property
* is not defined.
*/
public int getIntProp(int propType) {
PropListItem item = lookupProperty(propType);
if (item == null) {
return 0;
}
return item.intValue;
}
public int getExistingIntProp(int propType) {
PropListItem item = lookupProperty(propType);
if (item == null) {
Kit.codeBug();
}
return item.intValue;
}
public void putProp(int propType, Object value) {
removeProp(propType);
if (value != null) {
propListHead = new PropListItem(propType, value, propListHead);
}
}
public void putBooleanProp(int propType, boolean value)
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {
putIntProp(propType, value ? 1 : 0);
}
public void putIntProp(int propType, int value) {
removeProp(propType);
if (value != 0) {
propListHead = new PropListItem(propType, value, propListHead);
}
}
// Gets all the property types, in sorted order.
private int[] getSortedPropTypes() {
int count = 0;
for (PropListItem x = propListHead; x != null; x = x.next) {
count++;
}
int[] keys = new int[count];
for (PropListItem x = propListHead; x != null; x = x.next) {
count--;
keys[count] = x.type;
}
Arrays.sort(keys);
return keys;
}
public int getLineno() {
return extractLineno(sourcePosition);
}
public int getCharno() {
return extractCharno(sourcePosition);
}
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
public double getDouble() throws UnsupportedOperationException {
if (this.getType() == Token.NUMBER) {
throw new IllegalStateException(
"Number node not created with Node.newNumber");
} else {
throw new UnsupportedOperationException(this + " is not a number node");
}
}
/** Can only be called when <tt>getType() == TokenStream.NUMBER</tt> */
public void setDouble(double s) throws UnsupportedOperationException {
if (this.getType() == Token.NUMBER) {
throw new IllegalStateException(
"Number node not created with Node.newNumber");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
/** Can only be called when node has String context. */
public String getString() throws UnsupportedOperationException {
if (this.getType() == Token.STRING) {
throw new IllegalStateException(
"String node not created with Node.newString");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
/** Can only be called when node has String context. */
public void setString(String s) throws UnsupportedOperationException {
if (this.getType() == Token.STRING) {
throw new IllegalStateException(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> "String node not created with Node.newString");
} else {
throw new UnsupportedOperationException(this + " is not a string node");
}
}
@Override
public String toString() {
return toString(true, true, true);
}
public String toString(
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
StringBuilder sb = new StringBuilder();
toString(sb, printSource, printAnnotations, printType);
return sb.toString();
}
return String.valueOf(type);
}
private void toString(
StringBuilder sb,
boolean printSource,
boolean printAnnotations,
boolean printType) {
if (Token.printTrees) {
sb.append(Token.name(type));
if (this instanceof StringNode) {
sb.append(' ');
sb.append(getString());
} else if (type == Token.FUNCTION) {
sb.append(' ');
// In the case of JsDoc trees, the first child is often not a string
// which causes exceptions to be thrown when calling toString or
// toStringTree.
if (first == null || first.getType() != Token.NAME) {
sb.append("<invalid>");
} else {
sb.append(first.getString());
}
} else if (this instanceof ScriptOrFnNode) {
ScriptOrFnNode sof = (ScriptOrFnNode) this;
if (this instanceof FunctionNode) {
FunctionNode fn = (FunctionNode) this;
sb.append(' ');
sb.append(fn.getFunctionName());
}
if (printSource) {
sb.append(" [source name: ");
sb.append(sof.getSourceName());
sb.append("] [encoded source length: ");
sb.append(sof.getEncodedSourceEnd() - sof.getEncodedSourceStart());
sb.append("] [base line: ");
sb.append(sof.getBaseLineno());
sb.append("] [end line: ");
sb.append(sof.getEndLineno());
sb.append(']');
}
} else if (type == Token.NUMBER) {
sb.append(' ');
sb.append(getDouble());
}
if (printSource) {
int lineno = getLineno();
if (lineno != -
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>1) {
sb.append(' ');
sb.append(lineno);
}
}
if (printAnnotations) {
int[] keys = getSortedPropTypes();
for (int i = 0; i < keys.length; i++) {
int type = keys[i];
PropListItem x = lookupProperty(type);
sb.append(" [");
sb.append(propToString(type));
sb.append(": ");
String value;
switch (type) {
case TARGETBLOCK_PROP: // can't add this as it recurses
value = "target block property";
break;
case LOCAL_BLOCK_PROP: // can't add this as it is dull
value = "last local block";
break;
case ISNUMBER_PROP:
switch (x.intValue) {
case BOTH:
value = "both";
break;
case RIGHT:
value = "right";
break;
case LEFT:
value = "left";
break;
default:
throw Kit.codeBug();
}
break;
case SPECIALCALL_PROP:
switch (x.intValue) {
case SPECIALCALL_EVAL:
value = "eval";
break;
case SPECIALCALL_WITH:
value = "with";
break;
default:
// NON_SPECIALCALL should not be stored
throw Kit.codeBug();
}
break;
default:
Object obj = x.objectValue;
if (obj != null) {
value = obj.toString();
} else {
value = String.valueOf(x.intValue);
}
break;
}
sb.append(value);
sb.append(']');
}
}
if (printType) {
if (jsType != null) {
String jsTypeString = jsType.toString();
if (jsTypeString != null) {
sb.append(" : ");
sb.append(jsTypeString);
}
}
}
}
}
public String toStringTree() {
return toStringTreeImpl();
}
private String toStringTreeImpl() {
try {
StringBuilder s = new StringBuilder();
appendStringTree(s);
return s.toString();
} catch (IOException e) {
throw new RuntimeException("Should not happen\n" + e);
}
}
public void appendStringTree(Append
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>able appendable) throws IOException {
toStringTreeHelper(this, 0, appendable);
}
private static void toStringTreeHelper(Node n, int level, Appendable sb)
throws IOException {
if (Token.printTrees) {
for (int i = 0; i != level; ++i) {
sb.append(" ");
}
sb.append(n.toString());
sb.append('\n');
for (Node cursor = n.getFirstChild();
cursor != null;
cursor = cursor.getNext()) {
toStringTreeHelper(cursor, level + 1, sb);
}
}
}
int type; // type of the node; Token.NAME for example
Node next; // next sibling
private Node first; // first element of a linked list of children
private Node last; // last element of a linked list of children
/**
* Linked list of properties. Since vast majority of nodes would have
* no more then 2 properties, linked list saves memory and provides
* fast lookup. If this does not holds, propListHead can be replaced
* by UintMap.
*/
private PropListItem propListHead;
/**
* COLUMN_BITS represents how many of the lower-order bits of
* sourcePosition are reserved for storing the column number.
* Bits above these store the line number.
* This gives us decent position information for everything except
* files already passed through a minimizer, where lines might
* be longer than 4096 characters.
*/
public static final int COLUMN_BITS = 12;
/**
* MAX_COLUMN_NUMBER represents the maximum column number that can
* be represented. JSCompiler's modifications to Rhino cause all
* tokens located beyond the maximum column to MAX_COLUMN_NUMBER.
*/
public static final int MAX_COLUMN_NUMBER = (1 << COLUMN_BITS) - 1;
/**
* COLUMN_MASK stores a value where bits storing the column number
* are set, and bits storing the line are not set. It's handy for
* separating column number from line number.
*/
public static final int COLUMN_MASK = MAX_COLUMN_NUMBER;
/**
* Source position of this node. The position is encoded with the
* column number in the low 12 bits of
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> return "script";
case Token.EMPTY: return "empty";
case Token.GET_REF: return "get_ref";
case Token.REF_SPECIAL: return "ref_special";
}
return "<unknown="+token+">";
}
/** Returns true if this node is equivalent semantically to another */
public boolean isEquivalentTo(Node node) {
return isEquivalentTo(node, false, true);
}
/**
* Returns true if this node is equivalent semantically to another and
* the types are equivalent.
*/
public boolean isEquivalentToTyped(Node node) {
return isEquivalentTo(node, true, true);
}
/**
* @param compareJsType Whether to compare the JSTypes of the nodes.
* @param recurse Whether to compare the children of the current node, if
* not only the the count of the children are compared.
* @return Whether this node is equivalent semantically to the provided node.
*/
boolean isEquivalentTo(Node node, boolean compareJsType, boolean recurse) {
if (type != node.getType()
|| getChildCount() != node.getChildCount()
|| getNodeClass(this) != getNodeClass(node)) {
return false;
}
if (compareJsType && !JSType.isEquivalent(jsType, node.getJSType())) {
return false;
}
if (type == Token.ARRAYLIT) {
try {
int[] indices1 = (int[]) getProp(Node.SKIP_INDEXES_PROP);
int[] indices2 = (int[]) node.getProp(Node.SKIP_INDEXES_PROP);
if (indices1 == null) {
if (indices2 != null) {
return false;
}
} else if (indices2 == null) {
return false;
} else if (indices1.length != indices2.length) {
return false;
} else {
for (int i = 0; i < indices1.length; i++) {
if (indices1[i] != indices2[i]) {
return false;
}
}
}
} catch (Exception e) {
return false;
}
} else if (type == Token.INC || type == Token.DEC) {
int post1 = this.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
child != null; child = child.getNext()) {
child.copyInformationFromForTree(other);
}
return this;
}
//==========================================================================
// Custom annotations
public JSType getJSType() {
return jsType;
}
public void setJSType(JSType jsType) {
this.jsType = jsType;
}
public FileLevelJsDocBuilder getJsDocBuilderForNode() {
return new FileLevelJsDocBuilder();
}
/**
* An inner class that provides back-door access to the license
* property of the JSDocInfo property for this node. This is only
* meant to be used for top level script nodes where the
* {@link com.google.javascript.jscomp.parsing.JsDocInfoParser} needs to
* be able to append directly to the top level node, not just the
* current node.
*/
public class FileLevelJsDocBuilder {
public void append(String fileLevelComment) {
JSDocInfo jsDocInfo = getJSDocInfo();
if (jsDocInfo == null) {
// TODO(user): Is there a way to determine whether to
// parse the JsDoc documentation from here?
jsDocInfo = new JSDocInfo(false);
}
String license = jsDocInfo.getLicense();
if (license == null) {
license = "";
}
jsDocInfo.setLicense(license + fileLevelComment);
setJSDocInfo(jsDocInfo);
}
}
/**
* Get the {@link JSDocInfo} attached to this node.
* @return the information or {@code null} if no JSDoc is attached to this
* node
*/
public JSDocInfo getJSDocInfo() {
return (JSDocInfo) getProp(JSDOC_INFO_PROP);
}
/**
* Sets the {@link JSDocInfo} attached to this node.
*/
public void setJSDocInfo(JSDocInfo info) {
putProp(JSDOC_INFO_PROP, info);
}
/**
* Sets whether this node is a variable length argument node. This
* method is meaningful only on {@link Token#NAME} nodes
* used to define a {@link Token#FUNCTION}'s argument list.
*/
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
public void setVarArgs(boolean varArgs) {
putBooleanProp(VAR_ARGS_NAME, varArgs);
}
/**
* Returns whether this node is a variable length argument node. This
* method's return value is meaningful only on {@link Token#NAME} nodes
* used to define a {@link Token#FUNCTION}'s argument list.
*/
public boolean isVarArgs() {
return getBooleanProp(VAR_ARGS_NAME);
}
/**
* Sets whether this node is an optional argument node. This
* method is meaningful only on {@link Token#NAME} nodes
* used to define a {@link Token#FUNCTION}'s argument list.
*/
public void setOptionalArg(boolean optionalArg) {
putBooleanProp(OPT_ARG_NAME, optionalArg);
}
/**
* Returns whether this node is an optional argument node. This
* method's return value is meaningful only on {@link Token#NAME} nodes
* used to define a {@link Token#FUNCTION}'s argument list.
*/
public boolean isOptionalArg() {
return getBooleanProp(OPT_ARG_NAME);
}
/**
* Sets whether this is a synthetic block that should not be considered
* a real source block.
*/
public void setIsSyntheticBlock(boolean val) {
putBooleanProp(SYNTHETIC_BLOCK_PROP, val);
}
/**
* Returns whether this is a synthetic block that should not be considered
* a real source block.
*/
public boolean isSyntheticBlock() {
return getBooleanProp(SYNTHETIC_BLOCK_PROP);
}
/**
* Sets the ES5 directives on this node.
*/
public void setDirectives(Set<String> val) {
putProp(DIRECTIVES, val);
}
/**
* Returns the set of ES5 directives for this node.
*/
@SuppressWarnings("unchecked")
public Set<String> getDirectives() {
return (Set<String>) getProp(DIRECTIVES);
}
/**
* Adds a warning to be suppressed. This is indistinguishable
* from having a {@code @suppress} tag in the code.
*/
public void addSuppression(String warning) {
if (getJSDocInfo() == null) {
setJSDocInfo
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(new JSDocInfo(false));
}
getJSDocInfo().addSuppression(warning);
}
/**
* Sets whether this is a synthetic block that should not be considered
* a real source block.
*/
public void setWasEmptyNode(boolean val) {
putBooleanProp(EMPTY_BLOCK, val);
}
/**
* Returns whether this is a synthetic block that should not be considered
* a real source block.
*/
public boolean wasEmptyNode() {
return getBooleanProp(EMPTY_BLOCK);
}
// There are four values of interest:
// global state changes
// this state changes
// arguments state changes
// whether the call throws an exception
// locality of the result
// We want a value of 0 to mean "global state changes and
// unknown locality of result".
final public static int FLAG_GLOBAL_STATE_UNMODIFIED = 1;
final public static int FLAG_THIS_UNMODIFIED = 2;
final public static int FLAG_ARGUMENTS_UNMODIFIED = 4;
final public static int FLAG_NO_THROWS = 8;
final public static int FLAG_LOCAL_RESULTS = 16;
final public static int SIDE_EFFECTS_FLAGS_MASK = 31;
final public static int SIDE_EFFECTS_ALL = 0;
final public static int NO_SIDE_EFFECTS =
FLAG_GLOBAL_STATE_UNMODIFIED
| FLAG_THIS_UNMODIFIED
| FLAG_ARGUMENTS_UNMODIFIED
| FLAG_NO_THROWS;
/**
* Marks this function or constructor call's side effect flags.
* This property is only meaningful for {@link Token#CALL} and
* {@link Token#NEW} nodes.
*/
public void setSideEffectFlags(int flags) {
Preconditions.checkArgument(
getType() == Token.CALL || getType() == Token.NEW,
"setIsNoSideEffectsCall only supports CALL and NEW nodes, got " +
Token.name(getType()));
putIntProp(SIDE_EFFECT_FLAGS, flags);
}
public void setSideEffectFlags(SideEffectFlags flags) {
setSideEffectFlags(flags.valueOf());
}
/**
* Returns the side effects flags for this node.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
*/
public int getSideEffectFlags() {
return getIntProp(SIDE_EFFECT_FLAGS);
}
/**
* A helper class for getting and setting the side-effect flags.
* @author johnlenz@google.com (John Lenz)
*/
public static class SideEffectFlags {
private int value = Node.SIDE_EFFECTS_ALL;
public SideEffectFlags() {
}
public SideEffectFlags(int value) {
this.value = value;
}
public int valueOf() {
return value;
}
/** All side-effect occur and the returned results are non-local. */
public void setAllFlags() {
value = Node.SIDE_EFFECTS_ALL;
}
/** No side-effects occur and the returned results are local. */
public void clearAllFlags() {
value = Node.NO_SIDE_EFFECTS | Node.FLAG_LOCAL_RESULTS;
}
public boolean areAllFlagsSet() {
return value == Node.SIDE_EFFECTS_ALL;
}
/**
* Preserve the return result flag, but clear the others:
* no global state change, no throws, no this change, no arguments change
*/
public void clearSideEffectFlags() {
value |= Node.NO_SIDE_EFFECTS;
}
public void setMutatesGlobalState() {
// Modify global means everything must be assumed to be modified.
removeFlag(Node.FLAG_GLOBAL_STATE_UNMODIFIED);
removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED);
removeFlag(Node.FLAG_THIS_UNMODIFIED);
}
public void setThrows() {
removeFlag(Node.FLAG_NO_THROWS);
}
public void setMutatesThis() {
removeFlag(Node.FLAG_THIS_UNMODIFIED);
}
public void setMutatesArguments() {
removeFlag(Node.FLAG_ARGUMENTS_UNMODIFIED);
}
public void setReturnsTainted() {
removeFlag(Node.FLAG_LOCAL_RESULTS);
}
private void removeFlag(int flag) {
value &= ~flag;
}
}
/**
* @return Whether the only side-effect is "modifies this"
*/
public boolean isOnlyModifiesThisCall() {
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
return areBitFlagsSet(
getSideEffectFlags() & Node.NO_SIDE_EFFECTS,
Node.FLAG_GLOBAL_STATE_UNMODIFIED
| Node.FLAG_ARGUMENTS_UNMODIFIED
| Node.FLAG_NO_THROWS);
}
/**
* Returns true if this node is a function or constructor call that
* has no side effects.
*/
public boolean isNoSideEffectsCall() {
return areBitFlagsSet(getSideEffectFlags(), NO_SIDE_EFFECTS);
}
/**
* Returns true if this node is a function or constructor call that
* returns a primitive or a local object (an object that has no other
* references).
*/
public boolean isLocalResultCall() {
return areBitFlagsSet(getSideEffectFlags(), FLAG_LOCAL_RESULTS);
}
/**
* returns true if all the flags are set in value.
*/
private boolean areBitFlagsSet(int value, int flags) {
return (value & flags) == flags;
}
/**
* This should only be called for STRING nodes children of OBJECTLIT.
*/
public boolean isQuotedString() {
return false;
}
/**
* This should only be called for STRING nodes children of OBJECTLIT.
*/
public void setQuotedString() {
Kit.codeBug();
}
static class NodeMismatch {
final Node nodeA;
final Node nodeB;
NodeMismatch(Node nodeA, Node nodeB) {
this.nodeA = nodeA;
this.nodeB = nodeB;
}
@Override
public boolean equals(Object object) {
if (object instanceof NodeMismatch) {
NodeMismatch that = (NodeMismatch) object;
return that.nodeA.equals(this.nodeA) && that.nodeB.equals(this.nodeB);
}
return false;
}
@Override
public int hashCode() {
return Objects.hashCode(nodeA, nodeB);
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> public boolean isNullable() {
return false;
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
if (that.isUnknownType() || that.isSubtype(
getNativeType(JSTypeNative.OBJECT_NUMBER_STRING_BOOLEAN))) {
return UNKNOWN;
}
return FALSE;
}
@Override
public boolean isNumberValueType() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
// TODO(user): Revisit this for ES4, which is stricter.
return true;
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public String getDisplayName() {
return "number";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.BOTH;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNumberType();
}
@Override
public JSType autoboxesTo() {
return getNativeType(JSTypeNative.NUMBER_OBJECT_TYPE);
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> constructor, false);
}
InstanceObjectType(JSTypeRegistry registry, FunctionType constructor,
boolean isNativeType) {
super(registry, null, null, isNativeType);
Preconditions.checkNotNull(constructor);
this.constructor = constructor;
}
@Override
public String getReferenceName() {
return getConstructor().getReferenceName();
}
@Override
public boolean hasReferenceName() {
return getConstructor().hasReferenceName();
}
@Override
public ObjectType getImplicitPrototype() {
return getConstructor().getPrototype();
}
@Override
public FunctionType getConstructor() {
return constructor;
}
@Override
boolean defineProperty(String name, JSType type, boolean inferred,
boolean inExterns, Node propertyNode) {
ObjectType proto = getImplicitPrototype();
if (proto != null && proto.hasOwnDeclaredProperty(name)) {
return false;
}
return super.defineProperty(name, type, inferred, inExterns, propertyNode);
}
@Override
public String toString() {
if (constructor.hasReferenceName()) {
return constructor.getReferenceName();
} else {
return super.toString();
}
}
@Override
boolean isTheObjectType() {
return getConstructor().isNative() && "Object".equals(getReferenceName());
}
@Override
public boolean isInstanceType() {
return true;
}
@Override
public boolean isArrayType() {
return getConstructor().isNative() && "Array".equals(getReferenceName());
}
@Override
public boolean isStringObjectType() {
return getConstructor().isNative() && "String".equals(getReferenceName());
}
@Override
public boolean isBooleanObjectType() {
return getConstructor().isNative() && "Boolean".equals(getReferenceName());
}
@Override
public boolean isNumberObjectType() {
return getConstructor().isNative() && "Number".equals(getReferenceName());
}
@Override
public boolean isDateType() {
return getConstructor().isNative() && "Date".equals(getReferenceName());
}
@Override
public boolean isRegexpType() {
return getConstructor().isNative() && "RegExp".equals(getReferenceName());
}
@Override
public boolean isNominalType() {
return hasReferenceName();
}
@Override
public boolean
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>ErrorReporter(null, new String[] { "first warning" });
* ...
* assertTrue(e.hasEncounteredAllWarnings());
* </pre>
*
*/
public final class TestErrorReporter extends Assert implements ErrorReporter {
private String[] errors;
private String[] warnings;
private int errorsIndex = 0;
private int warningsIndex = 0;
public TestErrorReporter(String[] errors, String[] warnings) {
this.errors = errors;
this.warnings = warnings;
}
public static TestErrorReporter forNoExpectedReports() {
return new TestErrorReporter(null, null);
}
public void setErrors(String[] errors) {
this.errors = errors;
errorsIndex = 0;
}
public void setWarnings(String[] warnings) {
this.warnings = warnings;
warningsIndex = 0;
}
public void error(String message, String sourceName, int line,
String lineSource, int lineOffset) {
if (errors != null && errorsIndex < errors.length) {
assertEquals(errors[errorsIndex++], message);
} else {
fail("extra error: " + message);
}
}
public void warning(String message, String sourceName, int line,
String lineSource, int lineOffset) {
if (warnings != null && warningsIndex < warnings.length) {
assertEquals(warnings[warningsIndex++], message);
} else {
fail("extra warning: " + message);
}
}
public EvaluatorException runtimeError(String message, String sourceName,
int line, String lineSource, int lineOffset) {
throw new UnsupportedOperationException();
}
/**
* Returns whether all warnings were reported to this reporter.
*/
public boolean hasEncounteredAllWarnings() {
return (warnings == null) ?
warningsIndex == 0 :
warnings.length == warningsIndex;
}
/**
* Returns whether all errors were reported to this reporter.
*/
public boolean hasEncounteredAllErrors() {
return (errors == null) ?
errorsIndex == 0 :
errors.length == errorsIndex;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>;
NullType(JSTypeRegistry registry) {
super(registry);
}
@Override
public boolean isNullType() {
return true;
}
@Override
public boolean isNullable() {
return true;
}
@Override
public boolean matchesNumberContext() {
return true;
}
@Override
public boolean matchesObjectContext() {
return false;
}
@Override
public boolean matchesStringContext() {
return true;
}
@Override
public JSType restrictByNotNullOrUndefined() {
return registry.getNativeType(JSTypeNative.NO_TYPE);
}
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = super.testForEquality(that);
if (result != null) {
return result;
}
if (that.isNullType() || that.isVoidType()) {
return TRUE;
}
if (that.isUnknownType() || that.isNullable()) {
return UNKNOWN;
}
return FALSE;
}
@Override
public String toString() {
return getDisplayName();
}
@Override
public String getDisplayName() {
return "null";
}
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
return BooleanLiteralSet.FALSE;
}
@Override
public <T> T visit(Visitor<T> visitor) {
return visitor.caseNullType();
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> template type.
private TemplateType templateType;
private final boolean tolerateUndefinedValues;
/**
* The type registry has three modes, which control how type ASTs are
* converted to types in {@link #createFromTypeNodes}.
*/
public static enum ResolveMode {
/**
* Expressions are converted into Unknown blobs that can be
* resolved into complex types.
*/
LAZY_EXPRESSIONS,
/**
* Expressions are evaluated. If any names in the expression point to
* unknown types, then we create a proxy {@code NamedType} structure
* until the type can be resolved.
*
* This is the legacy way of resolving ways, and may not exist in the
* future.
*/
LAZY_NAMES,
/**
* Expressions and type names are evaluated aggressively. A warning
* will be emitted if a type name fails to resolve to a real type.
*/
IMMEDIATE
}
private ResolveMode resolveMode = ResolveMode.LAZY_NAMES;
/**
* Constructs a new type registry populated with the built-in types.
*/
public JSTypeRegistry(ErrorReporter reporter) {
this(reporter, false);
}
/**
* Constructs a new type registry populated with the built-in types.
*/
public JSTypeRegistry(
ErrorReporter reporter, boolean tolerateUndefinedValues) {
this.reporter = reporter;
nativeTypes = new JSType[JSTypeNative.values().length];
namesToTypes = new HashMap<String, JSType>();
resetForTypeCheck();
this.tolerateUndefinedValues = tolerateUndefinedValues;
}
/**
* Set the current resolving mode of the type registry.
* @see ResolveMode
*/
public void setResolveMode(ResolveMode mode) {
this.resolveMode = mode;
}
ResolveMode getResolveMode() {
return resolveMode;
}
public ErrorReporter getErrorReporter() {
return reporter;
}
public boolean shouldTolerateUndefinedValues() {
return tolerateUndefinedValues;
}
/**
* Reset to run the TypeCheck pass.
*/
public void resetForTypeCheck() {
typesIndexedByProperty.clear();
eachRefTypeIndexedByProperty.clear();
initializeBuiltInTypes();
namesToTypes.clear();
namespaces.clear();
initializeRegistry();
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> register(getNativeType(JSTypeNative.TYPE_ERROR_TYPE));
register(getNativeType(JSTypeNative.RANGE_ERROR_TYPE));
register(getNativeType(JSTypeNative.REFERENCE_ERROR_TYPE));
register(getNativeType(JSTypeNative.SYNTAX_ERROR_TYPE));
register(getNativeType(JSTypeNative.REGEXP_TYPE));
register(getNativeType(JSTypeNative.STRING_OBJECT_TYPE));
register(getNativeType(JSTypeNative.STRING_TYPE));
register(getNativeType(JSTypeNative.VOID_TYPE));
register(getNativeType(JSTypeNative.VOID_TYPE), "Undefined");
register(getNativeType(JSTypeNative.VOID_TYPE), "void");
register(getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE), "Function");
}
private void register(JSType type) {
register(type, type.toString());
}
private void register(JSType type, String name) {
namesToTypes.put(name, type);
// Add all the namespaces in which this name lives.
while (name.indexOf('.') > 0) {
name = name.substring(0, name.lastIndexOf('.'));
namespaces.add(name);
}
}
private void registerNativeType(JSTypeNative typeId, JSType type) {
nativeTypes[typeId.ordinal()] = type;
}
/**
* Tells the type system that {@code owner} may have a property named
* {@code propertyName}. This allows the registry to keep track of what
* types a property is defined upon.
*
* This is NOT the same as saying that {@code owner} must have a property
* named type. ObjectType#hasProperty attempts to minimize false positives
* ("if we're not sure, then don't type check this property"). The type
* registry, on the other hand, should attempt to minimize false negatives
* ("if this property is assigned anywhere in the program, it must
* show up in the type registry").
*/
public void registerPropertyOnType(String propertyName, JSType type) {
UnionTypeBuilder typeSet = typesIndexedByProperty.get(propertyName);
if (typeSet == null) {
typeSet = new UnionTypeBuilder(this);
typesIndexed
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
FunctionParamBuilder builder = new FunctionParamBuilder(this);
builder.addOptionalParams(parameterTypes);
return builder.build();
}
/**
* Creates a tree hierarchy representing a typed argument list.
*
* @param lastVarArgs whether the last type should considered as a variable
* length argument.
* @param parameterTypes the parameter types. The last element of this array
* is considered a variable length argument is {@code lastVarArgs} is
* {@code true}.
* @return a tree hierarchy representing a typed argument list
*/
private Node createParameters(boolean lastVarArgs, JSType... parameterTypes) {
FunctionParamBuilder builder = new FunctionParamBuilder(this);
int max = parameterTypes.length - 1;
for (int i = 0; i <= max; i++) {
if (lastVarArgs && i == max) {
builder.addVarArgs(parameterTypes[i]);
} else {
builder.addRequiredParams(parameterTypes[i]);
}
}
return builder.build();
}
/**
* Creates a function type.
* @param returnType the function's return type
* @param lastVarArgs whether the last parameter type should be considered as
* an extensible var_args parameter
* @param parameterTypes the parameters' types
*/
public FunctionType createFunctionType(JSType returnType,
boolean lastVarArgs, JSType... parameterTypes) {
if (lastVarArgs) {
return createFunctionTypeWithVarArgs(returnType, parameterTypes);
} else {
return createFunctionType(returnType, parameterTypes);
}
}
/**
* Creates a new function type based on an existing function type but
* with a new return type.
* @param existingFunctionType the existing function type.
* @param returnType the new return type.
*/
public FunctionType createFunctionTypeWithNewReturnType(
FunctionType existingFunctionType, JSType returnType) {
return new FunctionBuilder(this)
.copyFromOtherFunction(existingFunctionType)
.withReturnType(returnType)
.build();
}
/**
* Creates a new function type based on an existing function type but
* with a new {@code this} type.
* @param existingFunctionType the existing function type.
* @param thisType the new this type.
*/
public FunctionType createFunctionTypeWith
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> = current.getFirstChild();
for (Node arg = current.getFirstChild(); arg != null;
arg = arg.getNext()) {
if (arg.getType() == Token.ELLIPSIS) {
if (arg.getChildCount() == 0) {
paramBuilder.addVarArgs(getNativeType(UNKNOWN_TYPE));
} else {
paramBuilder.addVarArgs(
createFromTypeNodesInternal(
arg.getFirstChild(), sourceName, scope));
}
} else {
JSType type = createFromTypeNodesInternal(
arg, sourceName, scope);
if (arg.getType() == Token.EQUALS) {
boolean addSuccess = paramBuilder.addOptionalParams(type);
if (!addSuccess) {
reporter.warning(
ScriptRuntime.getMessage0("msg.jsdoc.function.varargs"),
sourceName, arg.getLineno(), "", arg.getCharno());
}
} else {
paramBuilder.addRequiredParams(type);
}
}
}
current = current.getNext();
}
JSType returnType =
createFromTypeNodesInternal(current, sourceName, scope);
return new FunctionBuilder(this)
.withParams(paramBuilder)
.withReturnType(returnType)
.withTypeOfThis(thisType)
.setIsConstructor(isConstructor)
.build();
}
throw new IllegalStateException(
"Unexpected node in type expression: " + n.toString());
}
/**
* Creates a RecordType from the nodes representing said record type.
* @param n The node with type info.
* @param sourceName The source file name.
* @param scope A scope for doing type name lookups.
*/
private JSType createRecordTypeFromNodes(Node n, String sourceName,
StaticScope<JSType> scope) {
RecordTypeBuilder builder = new RecordTypeBuilder(this);
// For each of the fields in the record type.
for (Node fieldTypeNode = n.getFirstChild();
fieldTypeNode != null;
fieldTypeNode = fieldTypeNode.getNext()) {
// Get the property's name.
Node fieldNameNode = fieldTypeNode;
boolean hasType = false;
if (fieldTypeNode.getType() == Token.COLON) {
fieldNameNode = fieldTypeNode.getFirstChild();
hasType = true;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
String fieldName = fieldNameNode.getString();
// TODO(user): Move this into the lexer/parser.
// Remove the string literal characters around a field name,
// if any.
if (fieldName.startsWith("'") || fieldName.startsWith("\"")) {
fieldName = fieldName.substring(1, fieldName.length() - 1);
}
// Get the property's type.
JSType fieldType = null;
if (hasType) {
// We have a declared type.
fieldType = createFromTypeNodesInternal(
fieldTypeNode.getLastChild(), sourceName, scope);
} else {
// Otherwise, the type is UNKNOWN.
fieldType = getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
// Add the property to the record.
if (builder.addProperty(fieldName, fieldType, fieldNameNode) == null) {
// Duplicate field name, warning and skip
reporter.warning(
"Duplicate record field " + fieldName,
sourceName,
n.getLineno(), "", fieldNameNode.getCharno());
}
}
return builder.build();
}
/**
* Sets the template type name.
*/
public void setTemplateTypeName(String name) {
templateTypeName = name;
templateType = new TemplateType(this, name);
}
/**
* Clears the template type name.
*/
public void clearTemplateTypeName() {
templateTypeName = null;
templateType = null;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {@code JSDocInfo}
* object being created.
*
*/
final public class JSDocInfoBuilder {
// the current JSDoc which is being populated
private JSDocInfo currentInfo;
// whether the current JSDocInfo has valuable information
private boolean populated = false;
// whether to include the documentation itself when parsing the JsDoc
private boolean parseDocumentation = false;
// the current marker, if any.
private JSDocInfo.Marker currentMarker = null;
public JSDocInfoBuilder(boolean parseDocumentation) {
this.currentInfo = new JSDocInfo(parseDocumentation);
this.parseDocumentation = parseDocumentation;
}
/**
* Sets the original JSDoc comment string. This is a no-op if the builder
* isn't configured to record documentation.
*/
public void recordOriginalCommentString(String sourceComment) {
if (parseDocumentation) {
currentInfo.setOriginalCommentString(sourceComment);
}
}
public boolean shouldParseDocumentation() {
return parseDocumentation;
}
/**
* Returns whether this builder is populated with information that can be
* used to {@link #build} a {@link JSDocInfo} object.
*/
public boolean isPopulated() {
return populated;
}
/**
* Returns whether this builder is populated with information that can be
* used to {@link #build} a {@link JSDocInfo} object that has a
* fileoverview tag.
*/
public boolean isPopulatedWithFileOverview() {
return isPopulated() &&
(currentInfo.hasFileOverview() || currentInfo.isExterns() ||
currentInfo.isNoCompile());
}
/**
* Returns whether this builder recorded a description.
*/
public boolean isDescriptionRecorded() {
return currentInfo.getDescription() != null;
}
/**
* Builds a {@link JSDocInfo} object based on the populated information and
* returns it. Once this method is called, the builder can be reused to build
* another {@link JSDocInfo} object.
*
* @param sourceName The source file containing the JSDoc.
* @return a {@link JSDocInfo} object populated with the values given to this
* builder. If no value was populated, this method simply
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> returns
* {@code null}
*/
public JSDocInfo build(String sourceName) {
if (populated) {
JSDocInfo built = currentInfo;
built.setSourceName(sourceName);
populateDefaults(built);
populated = false;
currentInfo = new JSDocInfo(this.parseDocumentation);
return built;
} else {
return null;
}
}
/** Generate defaults when certain parameters are not specified. */
private static void populateDefaults(JSDocInfo info) {
if (info.getVisibility() == null) {
info.setVisibility(Visibility.INHERITED);
}
}
/**
* Adds a marker to the current JSDocInfo and populates the marker with the
* annotation information.
*/
public void markAnnotation(String annotation, int lineno, int charno) {
JSDocInfo.Marker marker = currentInfo.addMarker();
if (marker != null) {
marker.annotation = new JSDocInfo.StringPosition();
marker.annotation.setItem(annotation);
marker.annotation.setPositionInformation(lineno, charno, lineno,
charno + annotation.length());
}
currentMarker = marker;
}
/**
* Adds a textual block to the current marker.
*/
public void markText(String text, int startLineno, int startCharno,
int endLineno, int endCharno) {
if (currentMarker != null) {
currentMarker.description = new JSDocInfo.StringPosition();
currentMarker.description.setItem(text);
currentMarker.description.setPositionInformation(startLineno, startCharno,
endLineno, endCharno);
}
}
/**
* Adds a type declaration to the current marker.
*/
public void markTypeNode(Node typeNode, int lineno, int startCharno,
int endCharno, boolean hasLC) {
if (currentMarker != null) {
currentMarker.type = new JSDocInfo.TypePosition();
currentMarker.type.setItem(typeNode);
currentMarker.type.hasBrackets = hasLC;
currentMarker.type.setPositionInformation(lineno, startCharno,
lineno, endCharno);
}
}
/**
* Adds a name declaration to
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> the current marker.
*/
public void markName(String name, int lineno, int charno) {
if (currentMarker != null) {
currentMarker.name = new JSDocInfo.StringPosition();
currentMarker.name.setItem(name);
currentMarker.name.setPositionInformation(lineno, charno,
lineno, charno + name.length());
}
}
/**
* Records a block-level description.
*
* @return {@code true} if the description was recorded.
*/
public boolean recordBlockDescription(String description) {
populated = true;
return currentInfo.documentBlock(description);
}
/**
* Records a visibility.
*
* @return {@code true} if the visibility was recorded and {@code false}
* if it was already defined
*/
public boolean recordVisibility(Visibility visibility) {
if (currentInfo.getVisibility() == null) {
populated = true;
currentInfo.setVisibility(visibility);
return true;
} else {
return false;
}
}
/**
* Records a typed parameter.
*
* @return {@code true} if the typed parameter was recorded and
* {@code false} if a parameter with the same name was already defined
*/
public boolean recordParameter(String parameterName, JSTypeExpression type) {
if (!hasAnySingletonTypeTags() &&
currentInfo.declareParam(type, parameterName)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records a parameter's description.
*
* @return {@code true} if the parameter's description was recorded and
* {@code false} if a parameter with the same name was already defined
*/
public boolean recordParameterDescription(
String parameterName, String description) {
if (currentInfo.documentParam(parameterName, description)) {
populated = true;
return true;
} else {
return false;
}
}
/**
* Records a template type name.
*
* @return {@code true} if the template type name was recorded and
* {@code false} if a template type name was already defined.
*/
public boolean recordTemplateTypeName(String name) {
if (currentInfo.declareTemplateTypeName(name)) {
populated =
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>;
import java.util.Comparator;
/**
* Represents JavaScript value types.<p>
*
* Types are split into two separate families: value types and object types.
*
* A special {@link UnknownType} exists to represent a wildcard type on which
* no information can be gathered. In particular, it can assign to everyone,
* is a subtype of everyone (and everyone is a subtype of it).<p>
*
* If you remove the {@link UnknownType}, the set of types in the type system
* forms a lattice with the {@link #isSubtype} relation defining the partial
* order of types. All types are united at the top of the lattice by the
* {@link AllType} and at the bottom by the {@link NoType}.<p>
*
*/
public abstract class JSType implements Serializable {
private static final long serialVersionUID = 1L;
private boolean resolved = false;
private JSType resolveResult = null;
public static final String UNKNOWN_NAME =
"Unknown class name";
public static final String NOT_A_CLASS =
"Not declared as a constructor";
public static final String NOT_A_TYPE =
"Not declared as a type name";
public static final String EMPTY_TYPE_COMPONENT =
"Named type with empty name component";
/**
* Total ordering on types based on their textual representation.
* This is used to have a deterministic output of the toString
* method of the union type since this output is used in tests.
*/
static final Comparator<JSType> ALPHA = new Comparator<JSType>() {
public int compare(JSType t1, JSType t2) {
return t1.toString().compareTo(t2.toString());
}
};
// A flag set on enum definition tree nodes
public static final int ENUMDECL = 1;
public static final int NOT_ENUMDECL = 0;
final JSTypeRegistry registry;
JSType(JSTypeRegistry registry) {
this.registry = registry;
}
/**
* Utility method for less verbose code.
*/
JSType getNativeType(JSTypeNative typeId) {
return registry.getNativeType(typeId);
}
/**
* Gets the docInfo for this type. By default, documentation cannot be
* attached to arbitrary
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> types. This must be overridden for
* programmer-defined types.
*/
public JSDocInfo getJSDocInfo() {
return null;
}
/**
* Returns a user meaningful label for the JSType instance. For example,
* Functions and Enums will return their declaration name (if they have one).
* Some types will not have a meaningful display name. Calls to
* hasDisplayName() will return true IFF getDisplayName() will return null
* or a zero length string.
*
* @return the display name of the type, or null if one is not available
*/
public String getDisplayName() {
return null;
}
/**
* @return true if the JSType has a user meaningful label.
*/
public boolean hasDisplayName() {
String displayName = getDisplayName();
return displayName != null && !displayName.isEmpty();
}
public boolean isNoType() {
return false;
}
public boolean isNoResolvedType() {
return false;
}
public boolean isNoObjectType() {
return false;
}
public final boolean isEmptyType() {
return isNoType() || isNoObjectType() || isNoResolvedType() ||
(registry.getNativeFunctionType(
JSTypeNative.LEAST_FUNCTION_TYPE) == this);
}
public boolean isNumberObjectType() {
return false;
}
public boolean isNumberValueType() {
return false;
}
/** Whether this is the prototype of a function. */
public boolean isFunctionPrototypeType() {
return false;
}
public boolean isStringObjectType() {
return false;
}
boolean isTheObjectType() {
return false;
}
public boolean isStringValueType() {
return false;
}
/**
* Tests whether the type is a string (value or Object).
* @return {@code this <: (String, string)}
*/
public final boolean isString() {
return this.isSubtype(
getNativeType(JSTypeNative.STRING_VALUE_OR_OBJECT_TYPE));
}
/**
* Tests whether the type is a number (value or Object).
* @return {@code this <: (Number, number)}
*/
public final boolean isNumber() {
return this.isSubtype(
getNativeType(JSTypeNative.NUMBER_VALUE
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>toString());
}
}
public void visit(NodeTraversal traversal, Node node, Node parent) {
Collection<Definition> defs =
passUnderTest.getDefinitionsReferencedAt(node);
if (defs != null) {
StringBuilder sb = new StringBuilder();
sb.append("USE ");
sb.append(Token.name(node.getType()));
sb.append(" ");
sb.append(node.getQualifiedName());
sb.append(" -> ");
Multiset<String> defstrs = TreeMultiset.create();
for (Definition def : defs) {
String defstr;
Node rValue = def.getRValue();
if (rValue != null) {
defstr = Token.name(rValue.getType());
} else {
defstr = "<null>";
}
if (def.isExtern()) {
defstr = "EXTERN " + defstr;
}
defstrs.add(defstr);
}
sb.append(defstrs.toString());
found.add(sb.toString());
}
}
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>util.Map;
import java.util.Set;
/**
* <p>JSDoc information describing JavaScript code. JSDoc is represented as a
* unified object with fields for each JSDoc annotation, even though some
* combinations are incorrect. For instance, if a JSDoc describes an enum,
* it cannot have information about a return type. This implementation
* takes advantage of such incompatibilities to reuse fields for multiple
* purposes, reducing memory consumption.</p>
*
* <p>Constructing {@link JSDocInfo} objects is simplified by
* {@link JSDocInfoBuilder} which provides early incompatibility detection.</p>
*
*/
public class JSDocInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* Visibility categories. The {@link Visibility#ordinal()} can be used as a
* numerical indicator of privacy, where 0 is the most private. This means
* that the {@link Visibility#compareTo} method can be used to
* determine if a visibility is more permissive than another.
*/
public enum Visibility {
PRIVATE,
PROTECTED,
PUBLIC,
// If visibility is not specified, we just assume that visibility
// is inherited from the super class.
INHERITED
}
private static final class LazilyInitializedInfo implements Serializable {
private static final long serialVersionUID = 1L;
// Function information
JSTypeExpression baseType = null;
List<JSTypeExpression> implementedInterfaces = null;
Map<String, JSTypeExpression> parameters = null;
List<JSTypeExpression> thrownTypes = null;
String templateTypeName = null;
// Other information
String description = null;
String meaning = null;
String deprecated = null;
String license = null;
Set<String> suppressions = null;
Set<String> modifies = null;
String lendsName = null;
}
private static final class LazilyInitializedDocumentation {
String sourceComment = null;
List<Marker> markers = null;
Map<String, String> parameters = null;
Map<JSTypeExpression, String> throwsDescriptions = null;
String blockDescription = null;
String fileOverview = null;
String returnDescription = null;
String version = null;
List<String> authors = null;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> MASK_NOSIDEEFFECTS = 0x00004000; // @nosideeffects
private static final int MASK_EXTERNS = 0x00008000; // @externs
private static final int MASK_JAVADISPATCH = 0x00010000; // @javadispath
private static final int MASK_NOCOMPILE = 0x00020000; // @nocompile
// 3 bit type field stored in the top 3 bits of the most significant
// nibble.
private static final int MASK_TYPEFIELD = 0xE0000000; // 1110...
private static final int TYPEFIELD_TYPE = 0x20000000; // 0010...
private static final int TYPEFIELD_RETURN = 0x40000000; // 0100...
private static final int TYPEFIELD_ENUM = 0x60000000; // 0110...
private static final int TYPEFIELD_TYPEDEF = 0x80000000; // 1000...
/**
* Creates a {@link JSDocInfo} object. This object should be created using
* a {@link JSDocInfoBuilder}.
*/
JSDocInfo(boolean includeDocumentation) {
this.includeDocumentation = includeDocumentation;
}
// Visible for testing.
public JSDocInfo() {}
void setConstant(boolean value) {
setFlag(value, MASK_CONSTANT);
}
void setConstructor(boolean value) {
setFlag(value, MASK_CONSTRUCTOR);
}
void setDefine(boolean value) {
setFlag(value, MASK_DEFINE);
}
void setHidden(boolean value) {
setFlag(value, MASK_HIDDEN);
}
void setNoCheck(boolean value) {
setFlag(value, MASK_NOCHECK);
}
void setShouldPreserveTry(boolean value) {
setFlag(value, MASK_PRESERVETRY);
}
void setOverride(boolean value) {
setFlag(value, MASK_OVERRIDE);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
void setNoAlias(boolean value) {
setFlag(value, MASK_NOALIAS);
}
// Visible for testing.
public void setDeprecated(boolean value) {
setFlag(value, MASK_DEPRECATED);
}
void setInterface(boolean value) {
setFlag(value, MASK_INTERFACE);
}
void setExport(boolean value) {
setFlag(value, MASK_EXPORT);
}
void setNoShadow(boolean value) {
setFlag(value, MASK_NOSHADOW);
}
void setImplicitCast(boolean value) {
setFlag(value, MASK_IMPLICITCAST);
}
void setNoSideEffects(boolean value) {
setFlag(value, MASK_NOSIDEEFFECTS);
}
void setExterns(boolean value) {
setFlag(value, MASK_EXTERNS);
}
void setJavaDispatch(boolean value) {
setFlag(value, MASK_JAVADISPATCH);
}
void setNoCompile(boolean value) {
setFlag(value, MASK_NOCOMPILE);
}
private void setFlag(boolean value, int mask) {
if (value) {
bitset |= mask;
} else {
bitset &= ~mask;
}
}
/**
* Returns whether the {@code @const} annotation is present on this
* {@link JSDocInfo}.
*/
public boolean isConstant() {
return getFlag(MASK_CONSTANT) || isDefine();
}
/**
* Returns whether the {@code @constructor} annotation is present on this
* {@link JSDocInfo}.
*/
public boolean isConstructor() {
return getFlag(MASK_CONSTRUCTOR);
}
/**
* Returns whether the {@code @define} annotation is present on this
* {@link JSDocInfo}. If this annotation is present, then the
* {@link #getType()} method will retrieve the define type.
*/
public boolean isDefine() {
return getFlag(MASK_DEFINE);
}
/**
* Returns whether the {@code @hidden} annotation is present on this
* {@link JSDocInfo}.
*/
public boolean isHidden() {
return getFlag(MASK_HIDDEN);
}
/**
* Returns whether the {@code @nocheck}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> assignments.
*/
public String getLendsName() {
return (info == null) ? null : info.lendsName;
}
void setLendsName(String name) {
lazyInitInfo();
info.lendsName = name;
}
/**
* Gets the description specified by the {@code @license} annotation.
*/
public String getLicense() {
return (info == null) ? null : info.license;
}
/** License directives can appear in multiple comments, and always
* apply to the entire file. Break protection and allow outsiders to
* update the license string so that we can attach the license text even
* when the JSDocInfo has been created and tagged with other information.
* @param license String containing new license text.
*/
public void setLicense(String license) {
lazyInitInfo();
info.license = license;
}
@Override
public String toString() {
return "JSDocInfo";
}
/**
* Returns whether this {@link JSDocInfo} contains a type for {@code @extends}
* annotation.
*/
public boolean hasBaseType() {
return getBaseType() != null;
}
/**
* Adds an implemented interface. Returns whether the interface was added. If
* the interface was already present in the list, it won't get added again.
*/
boolean addImplementedInterface(JSTypeExpression interfaceName) {
lazyInitInfo();
if (info.implementedInterfaces == null) {
info.implementedInterfaces = Lists.newArrayListWithCapacity(2);
}
if (info.implementedInterfaces.contains(interfaceName)) {
return false;
}
info.implementedInterfaces.add(interfaceName);
return true;
}
/**
* Returns the types specified by the {@code @implements} annotation.
*
* @return An immutable list of JSTypeExpression objects that can
* be resolved to types.
*/
public List<JSTypeExpression> getImplementedInterfaces() {
if (info == null || info.implementedInterfaces == null) {
return ImmutableList.of();
}
return Collections.unmodifiableList(info.implementedInterfaces);
}
/**
* Gets the number of interfaces specified by the {@code @implements}
* annotation.
*/
public int getImplementedInterfaceCount() {
if
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> all types declared. Declares newly discovered types
* and type properties in the type registry.
*/
public Scope createScope(Node root, Scope parent) {
// Constructing the global scope is very different than constructing
// inner scopes, because only global scopes can contain named classes that
// show up in the type registry.
Scope newScope = null;
AbstractScopeBuilder scopeBuilder = null;
if (parent == null) {
// Find all the classes in the global scope.
newScope = createInitialScope(root);
GlobalScopeBuilder globalScopeBuilder = new GlobalScopeBuilder(newScope);
scopeBuilder = globalScopeBuilder;
NodeTraversal.traverse(compiler, root, scopeBuilder);
} else {
newScope = new Scope(parent, root);
LocalScopeBuilder localScopeBuilder = new LocalScopeBuilder(newScope);
scopeBuilder = localScopeBuilder;
localScopeBuilder.build();
}
scopeBuilder.resolveStubDeclarations();
scopeBuilder.resolveTypes();
// Gather the properties in each function that we found in the
// global scope, if that function has a @this type that we can
// build properties on.
for (Node functionNode : scopeBuilder.nonExternFunctions) {
JSType type = functionNode.getJSType();
if (type != null && type instanceof FunctionType) {
FunctionType fnType = (FunctionType) type;
ObjectType fnThisType = fnType.getTypeOfThis();
if (!fnThisType.isUnknownType()) {
NodeTraversal.traverse(compiler, functionNode.getLastChild(),
scopeBuilder.new CollectProperties(fnThisType));
}
}
}
if (parent == null) {
codingConvention.defineDelegateProxyPrototypeProperties(
typeRegistry, newScope, delegateProxyPrototypes);
}
return newScope;
}
/**
* Create the outermost scope. This scope contains native binding such as
* {@code Object}, {@code Date}, etc.
*/
@VisibleForTesting
Scope createInitialScope(Node root) {
NodeTraversal.traverse(
compiler, root, new DiscoverEnumsAndTypedefs(typeRegistry));
Scope s = new Scope(root, compiler);
declareNativeFunctionType(s, ARRAY_FUNCTION_TYPE);
declareNativeFunctionType(s, BOOLEAN_OBJECT_FUNCTION_TYPE);
declareNative
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>FunctionType(s, DATE_FUNCTION_TYPE);
declareNativeFunctionType(s, ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, EVAL_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, FUNCTION_FUNCTION_TYPE);
declareNativeFunctionType(s, NUMBER_OBJECT_FUNCTION_TYPE);
declareNativeFunctionType(s, OBJECT_FUNCTION_TYPE);
declareNativeFunctionType(s, RANGE_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, REFERENCE_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, REGEXP_FUNCTION_TYPE);
declareNativeFunctionType(s, STRING_OBJECT_FUNCTION_TYPE);
declareNativeFunctionType(s, SYNTAX_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, TYPE_ERROR_FUNCTION_TYPE);
declareNativeFunctionType(s, URI_ERROR_FUNCTION_TYPE);
declareNativeValueType(s, "undefined", VOID_TYPE);
// The typedef construct needs the any type, so that it can be assigned
// to anything. This is kind of a hack, and an artifact of the typedef
// syntax we've chosen.
declareNativeValueType(s, LEGACY_TYPEDEF, NO_TYPE);
// ActiveXObject is unqiuely special, because it can be used to construct
// any type (the type that it creates is related to the arguments you
// pass to it).
declareNativeValueType(s, "ActiveXObject", NO_OBJECT_TYPE);
return s;
}
private void declareNativeFunctionType(Scope scope, JSTypeNative tId) {
FunctionType t = typeRegistry.getNativeFunctionType(tId);
declareNativeType(scope, t.getInstanceType().getReferenceName(), t);
declareNativeType(
scope, t.getPrototype().getReferenceName(), t.getPrototype());
}
private void declareNativeValueType(Scope scope, String name,
JSTypeNative tId) {
declareNativeType(scope, name, typeRegistry.getNativeType(tId));
}
private void declareNativeType(Scope scope, String name, JSType t) {
scope.declare(name, null, t, null, false);
}
private static class DiscoverEnumsAndTypedefs
extends AbstractShallowStatementCallback {
private final JSTypeRegistry registry;
DiscoverEnumsAndTypedefs(JSType
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Registry registry) {
this.registry = registry;
}
@Override
public void visit(NodeTraversal t, Node node, Node parent) {
Node nameNode = null;
switch (node.getType()) {
case Token.VAR:
for (Node child = node.getFirstChild();
child != null; child = child.getNext()) {
identifyNameNode(
child, child.getFirstChild(),
NodeUtil.getInfoForNameNode(child));
}
break;
case Token.EXPR_RESULT:
Node firstChild = node.getFirstChild();
if (firstChild.getType() == Token.ASSIGN) {
identifyNameNode(
firstChild.getFirstChild(), firstChild.getLastChild(),
firstChild.getJSDocInfo());
} else {
identifyNameNode(
firstChild, null, firstChild.getJSDocInfo());
}
break;
}
}
private void identifyNameNode(
Node nameNode, Node valueNode, JSDocInfo info) {
if (nameNode.isQualifiedName()) {
if (info != null) {
if (info.hasEnumParameterType()) {
registry.identifyNonNullableName(nameNode.getQualifiedName());
} else if (info.hasTypedefType()) {
registry.identifyNonNullableName(nameNode.getQualifiedName());
}
}
if (valueNode != null &&
LEGACY_TYPEDEF.equals(valueNode.getQualifiedName())) {
registry.identifyNonNullableName(nameNode.getQualifiedName());
}
}
}
}
/**
* Given a node, determines whether that node names a prototype
* property, and if so, returns the qualified name node representing
* the owner of that property. Otherwise, returns null.
*/
private static Node getPrototypePropertyOwner(Node n) {
if (n.getType() == Token.GETPROP) {
Node firstChild = n.getFirstChild();
if (firstChild.getType() == Token.GETPROP &&
firstChild.getLastChild().getString().equals("prototype")) {
Node maybeOwner = firstChild.getFirstChild();
if (maybeOwner.isQualifiedName()) {
return maybeOwner;
}
}
}
return null;
}
private JSType getNativeType(JSTypeNative nativeType) {
return typeRegistry.getNativeType(
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
case Token.NUMBER:
// Defer keys to the Token.OBJECTLIT case
if (!NodeUtil.isObjectLitKey(n, n.getParent())) {
n.setJSType(getNativeType(NUMBER_TYPE));
}
break;
case Token.TRUE:
case Token.FALSE:
n.setJSType(getNativeType(BOOLEAN_TYPE));
break;
case Token.REGEXP:
n.setJSType(getNativeType(REGEXP_TYPE));
break;
case Token.REF_SPECIAL:
n.setJSType(getNativeType(UNKNOWN_TYPE));
break;
case Token.OBJECTLIT:
defineObjectLiteral(t, n);
break;
// NOTE(nicksantos): If we ever support Array tuples,
// we will need to put ARRAYLIT here as well.
}
}
private void defineObjectLiteral(NodeTraversal t, Node objectLit) {
// Handle the @lends annotation.
JSType type = null;
JSDocInfo info = objectLit.getJSDocInfo();
if (info != null &&
info.getLendsName() != null) {
String lendsName = info.getLendsName();
Var lendsVar = scope.getVar(lendsName);
if (lendsVar == null) {
compiler.report(
JSError.make(sourceName, objectLit, UNKNOWN_LENDS, lendsName));
} else {
type = lendsVar.getType();
if (type == null) {
type = typeRegistry.getNativeType(UNKNOWN_TYPE);
}
if (!type.isSubtype(typeRegistry.getNativeType(OBJECT_TYPE))) {
compiler.report(
JSError.make(sourceName, objectLit, LENDS_ON_NON_OBJECT,
lendsName, type.toString()));
type = null;
} else {
objectLit.setJSType(type);
}
}
}
info = getBestJSDocInfo(objectLit);
Node lValue = getBestLValue(objectLit);
String lValueName = getBestLValueName(lValue);
boolean createdEnumType = false;
if (info != null && info.hasEnumParameterType()) {
type = createEnumTypeFromNodes
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>(objectLit, lValueName, info, lValue);
createdEnumType = true;
}
if (type == null) {
type = typeRegistry.createAnonymousObjectType();
}
setDeferredType(objectLit, type);
// If this is an enum, the properties were already taken care of above.
if (!createdEnumType) {
processObjectLitProperties(
t, objectLit, ObjectType.cast(objectLit.getJSType()));
}
}
/**
* Process an object literal and all the types on it.
* @param objLit The OBJECTLIT node.
* @param objLitType The type of the OBJECTLIT node. This might be a named
* type, because of the lends annotation.
*/
void processObjectLitProperties(
NodeTraversal t, Node objLit, ObjectType objLitType) {
for (Node keyNode = objLit.getFirstChild(); keyNode != null;
keyNode = keyNode.getNext()) {
Node value = keyNode.getFirstChild();
String memberName = NodeUtil.getObjectLitKeyName(keyNode);
JSDocInfo info = keyNode.getJSDocInfo();
JSType valueType = getDeclaredType(
t.getSourceName(), info, keyNode, value);
JSType keyType = NodeUtil.getObjectLitKeyTypeFromValueType(
keyNode, valueType);
if (keyType != null) {
// Try to declare this property in the current scope if it
// has an authoritative name.
String qualifiedName = getBestLValueName(keyNode);
if (qualifiedName != null) {
defineSlot(keyNode, objLit, qualifiedName, keyType, false);
} else {
setDeferredType(keyNode, keyType);
}
if (objLitType != null) {
// Declare this property on its object literal.
boolean isExtern = t.getInput() != null && t.getInput().isExtern();
objLitType.defineDeclaredProperty(
memberName, keyType, isExtern, keyNode);
}
}
}
}
/**
* Returns the type specified in a JSDoc annotation near a GETPROP or NAME.
*
* Extracts type information from either the {@code @type} tag or from
* the {@code @return} and
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> {@code @param} tags.
*/
private JSType getDeclaredTypeInAnnotation(String sourceName,
Node node, JSDocInfo info) {
JSType jsType = null;
Node objNode =
node.getType() == Token.GETPROP ? node.getFirstChild() :
NodeUtil.isObjectLitKey(node, node.getParent()) ? node.getParent() :
null;
if (info != null) {
if (info.hasType()) {
jsType = info.getType().evaluate(scope, typeRegistry);
} else if (FunctionTypeBuilder.isFunctionTypeDeclaration(info)) {
String fnName = node.getQualifiedName();
jsType = createFunctionTypeFromNodes(
null, fnName, info, node);
}
}
return jsType;
}
/**
* Asserts that it's ok to define this node's name.
* The node should have a source name and be of the specified type.
*/
void assertDefinitionNode(Node n, int type) {
Preconditions.checkState(sourceName != null);
Preconditions.checkState(n.getType() == type);
}
/**
* Defines a catch parameter.
*/
void defineCatch(Node n, Node parent) {
assertDefinitionNode(n, Token.CATCH);
Node catchName = n.getFirstChild();
defineSlot(catchName, n, null);
}
/**
* Defines a VAR initialization.
*/
void defineVar(Node n, Node parent) {
assertDefinitionNode(n, Token.VAR);
JSDocInfo info = n.getJSDocInfo();
if (n.hasMoreThanOneChild()) {
if (info != null) {
// multiple children
compiler.report(JSError.make(sourceName, n, MULTIPLE_VAR_DEF));
}
for (Node name : n.children()) {
defineName(name, n, parent, name.getJSDocInfo());
}
} else {
Node name = n.getFirstChild();
defineName(name, n, parent,
(info != null) ? info : name.getJSDocInfo());
}
}
/**
* Defines a function literal.
*/
void defineFunctionLiteral(Node n, Node parent) {
assertDefinitionNode(n, Token.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>FUNCTION);
// Determine the name and JSDocInfo and lvalue for the function.
// Any of these may be null.
Node lValue = getBestLValue(n);
JSDocInfo info = getBestJSDocInfo(n);
String functionName = getBestLValueName(lValue);
FunctionType functionType =
createFunctionTypeFromNodes(n, functionName, info, lValue);
// Assigning the function type to the function node
setDeferredType(n, functionType);
// Declare this symbol in the current scope iff it's a function
// declaration. Otherwise, the declaration will happen in other
// code paths.
if (NodeUtil.isFunctionDeclaration(n)) {
defineSlot(n.getFirstChild(), n, functionType);
}
}
/**
* Defines a variable based on the {@link Token#NAME} node passed.
* @param name The {@link Token#NAME} node.
* @param var The parent of the {@code name} node, which must be a
* {@link Token#VAR} node.
* @param parent {@code var}'s parent.
* @param info the {@link JSDocInfo} information relating to this
* {@code name} node.
*/
private void defineName(Node name, Node var, Node parent, JSDocInfo info) {
Node value = name.getFirstChild();
// variable's type
JSType type = getDeclaredType(sourceName, info, name, value);
if (type == null) {
// The variable's type will be inferred.
CompilerInput input = compiler.getInput(sourceName);
Preconditions.checkNotNull(input, sourceName);
type = input.isExtern() ?
getNativeType(UNKNOWN_TYPE) : null;
}
defineSlot(name, var, type);
}
/**
* If a variable is assigned a function literal in the global scope,
* make that a declared type (even if there's no doc info).
* There's only one exception to this rule:
* if the return type is inferred, and we're in a local
* scope, we should assume the whole function is inferred.
*/
private boolean shouldUseFunctionLiteralType(
FunctionType type, JSDocInfo info, Node lValue) {
if
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> (info != null) {
return true;
}
if (lValue != null &&
NodeUtil.isObjectLitKey(lValue, lValue.getParent())) {
return false;
}
return scope.isGlobal() || !type.isReturnTypeInferred();
}
/**
* Creates a new function type, based on the given nodes.
*
* This handles two cases that are semantically very different, but
* are not mutually exclusive:
* - A function literal that needs a type attached to it.
* - An assignment expression with function-type info in the jsdoc.
*
* All parameters are optional, and we will do the best we can to create
* a function type.
*
* This function will always create a function type, so only call it if
* you're sure that's what you want.
*
* @param rValue The function node.
* @param name the function's name
* @param info the {@link JSDocInfo} attached to the function definition
* @param lvalueNode The node where this function is being
* assigned. For example, {@code A.prototype.foo = ...} would be used to
* determine that this function is a method of A.prototype. May be
* null to indicate that this is not being assigned to a qualified name.
*/
private FunctionType createFunctionTypeFromNodes(
@Nullable Node rValue,
@Nullable String name,
@Nullable JSDocInfo info,
@Nullable Node lvalueNode) {
FunctionType functionType = null;
// Global ctor aliases should be registered with the type registry.
if (rValue != null && rValue.isQualifiedName() && scope.isGlobal()) {
Var var = scope.getVar(rValue.getQualifiedName());
if (var != null && var.getType() instanceof FunctionType) {
FunctionType aliasedType = (FunctionType) var.getType();
if ((aliasedType.isConstructor() || aliasedType.isInterface()) &&
!aliasedType.isNativeObjectType()) {
functionType = aliasedType;
if (name != null && scope.isGlobal()) {
typeRegistry.declareType(name, functionType.getInstanceType());
}
}
}
}
if (functionType == null) {
Node error
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>Root = rValue == null ? lvalueNode : rValue;
boolean isFnLiteral =
rValue != null && rValue.getType() == Token.FUNCTION;
Node fnRoot = isFnLiteral ? rValue : null;
Node parametersNode = isFnLiteral ?
rValue.getFirstChild().getNext() : null;
Node fnBlock = isFnLiteral ? parametersNode.getNext() : null;
if (info != null && info.hasType()) {
JSType type = info.getType().evaluate(scope, typeRegistry);
// Known to be not null since we have the FUNCTION token there.
type = type.restrictByNotNullOrUndefined();
if (type.isFunctionType()) {
functionType = (FunctionType) type;
functionType.setJSDocInfo(info);
}
}
if (functionType == null) {
// Find the type of any overridden function.
FunctionType overriddenPropType = null;
if (lvalueNode != null &&
lvalueNode.getType() == Token.GETPROP &&
lvalueNode.isQualifiedName()) {
Var var = scope.getVar(
lvalueNode.getFirstChild().getQualifiedName());
if (var != null) {
ObjectType ownerType = ObjectType.cast(var.getType());
if (ownerType != null) {
String propName = lvalueNode.getLastChild().getString();
overriddenPropType =
findOverriddenFunction(ownerType, propName);
}
}
}
FunctionTypeBuilder builder =
new FunctionTypeBuilder(name, compiler, errorRoot, sourceName,
scope)
.setSourceNode(fnRoot)
.inferFromOverriddenFunction(overriddenPropType, parametersNode)
.inferTemplateTypeName(info)
.inferReturnType(info)
.inferInheritance(info);
// Infer the context type.
boolean searchedForThisType = false;
if (lvalueNode != null &&
lvalueNode.getType() == Token.GETPROP) {
Node objNode = lvalueNode.getFirstChild();
if (objNode.getType() == Token.GETPROP &&
objNode.getLastChild().getString().equals("prototype")) {
builder.inferThisType(info, objNode.getFirstChild());
searchedForThisType = true;
} else if (objNode.getType() == Token
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.THIS) {
builder.inferThisType(info, objNode.getJSType());
searchedForThisType = true;
}
}
if (!searchedForThisType) {
builder.inferThisType(info, (Node) null);
}
functionType = builder
.inferParameterTypes(parametersNode, info)
.inferReturnStatementsAsLastResort(fnBlock)
.buildAndRegister();
}
}
// all done
return functionType;
}
/**
* Find the function that's being overridden on this type, if any.
*/
private FunctionType findOverriddenFunction(
ObjectType ownerType, String propName) {
// First, check to see if the property is implemented
// on a superclass.
JSType propType = ownerType.getPropertyType(propName);
if (propType instanceof FunctionType) {
return (FunctionType) propType;
} else {
// If it's not, then check to see if it's implemented
// on an implemented interface.
for (ObjectType iface :
ownerType.getCtorImplementedInterfaces()) {
propType = iface.getPropertyType(propName);
if (propType instanceof FunctionType) {
return (FunctionType) propType;
}
}
}
return null;
}
/**
* Creates a new enum type, based on the given nodes.
*
* This handles two cases that are semantically very different, but
* are not mutually exclusive:
* - An object literal that needs an enum type attached to it.
* - An assignment expression with an enum tag in the jsdoc.
*
* This function will always create an enum type, so only call it if
* you're sure that's what you want.
*
* @param rValue The node of the enum.
* @param name The enum's name
* @param info The {@link JSDocInfo} attached to the enum definition.
* @param lvalueNode The node where this function is being
* assigned.
*/
private EnumType createEnumTypeFromNodes(Node rValue, String name,
JSDocInfo info, Node lValueNode) {
Preconditions.checkNotNull(info);
Preconditions.checkState(info.hasEnumParameterType());
EnumType enumType = null;
if (rValue != null &&
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> rValue.isQualifiedName()) {
// Handle an aliased enum.
Var var = scope.getVar(rValue.getQualifiedName());
if (var != null && var.getType() instanceof EnumType) {
enumType = (EnumType) var.getType();
}
}
if (enumType == null) {
JSType elementsType =
info.getEnumParameterType().evaluate(scope, typeRegistry);
enumType = typeRegistry.createEnumType(name, elementsType);
if (rValue != null && rValue.getType() == Token.OBJECTLIT) {
// collect enum elements
Node key = rValue.getFirstChild();
while (key != null) {
String keyName = NodeUtil.getStringValue(key);
if (keyName == null) {
// GET and SET don't have a String value;
compiler.report(
JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName));
} else if (enumType.hasOwnProperty(keyName)) {
compiler.report(JSError.make(sourceName, key, ENUM_DUP, keyName));
} else if (!codingConvention.isValidEnumKey(keyName)) {
compiler.report(
JSError.make(sourceName, key, ENUM_NOT_CONSTANT, keyName));
} else {
enumType.defineElement(keyName, key);
}
key = key.getNext();
}
}
}
if (name != null && scope.isGlobal()) {
typeRegistry.declareType(name, enumType.getElementsType());
}
return enumType;
}
/**
* Defines a typed variable. The defining node will be annotated with the
* variable's type or {@code null} if its type is inferred.
* @param name the defining node. It must be a {@link Token#NAME}.
* @param parent the {@code name}'s parent.
* @param type the variable's type. It may be {@code null}, in which case
* the variable's type will be inferred.
*/
private void defineSlot(Node name, Node parent, JSType type) {
defineSlot(name, parent, type, type == null);
}
/**
* Defines a typed variable. The defining node will be annotated with the
* variable's type
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> * @param lValue The l-value node.
* @param rValue The node that {@code n} is being initialized to,
* or {@code null} if this is a stub declaration.
*/
private JSType getDeclaredType(String sourceName, JSDocInfo info,
Node lValue, @Nullable Node rValue) {
if (info != null && info.hasType()) {
return getDeclaredTypeInAnnotation(sourceName, lValue, info);
} else if (rValue != null && rValue.getType() == Token.FUNCTION &&
shouldUseFunctionLiteralType(
(FunctionType) rValue.getJSType(), info, lValue)) {
return rValue.getJSType();
} else if (info != null) {
if (info.hasEnumParameterType()) {
if (rValue != null && rValue.getType() == Token.OBJECTLIT) {
return rValue.getJSType();
} else {
return createEnumTypeFromNodes(
rValue, lValue.getQualifiedName(), info, lValue);
}
} else if (info.isConstructor() || info.isInterface()) {
return createFunctionTypeFromNodes(
rValue, lValue.getQualifiedName(), info, lValue);
} else {
// Check if this is constant, and if it has a known type.
if (info.isConstant()) {
JSType knownType = null;
if (rValue != null) {
if (rValue.getJSType() != null
&& !rValue.getJSType().isUnknownType()) {
return rValue.getJSType();
} else if (rValue.getType() == Token.OR) {
// Check for a very specific JS idiom:
// var x = x || TYPE;
// This is used by Closure's base namespace for esoteric
// reasons.
Node firstClause = rValue.getFirstChild();
Node secondClause = firstClause.getNext();
boolean namesMatch = firstClause.getType() == Token.NAME
&& lValue.getType() == Token.NAME
&& firstClause.getString().equals(lValue.getString());
if (namesMatch && secondClause.getJSType() != null
&& !secondClause.getJSType().isUnknownType()) {
return secondClause.getJSType
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>.report(JSError.make(t.getSourceName(), n,
CONSTRUCTOR_EXPECTED));
}
}
}
/**
* Apply special properties that only apply to delegates.
*/
private void applyDelegateRelationship(
DelegateRelationship delegateRelationship) {
ObjectType delegatorObject = ObjectType.cast(
typeRegistry.getType(delegateRelationship.delegator));
ObjectType delegateBaseObject = ObjectType.cast(
typeRegistry.getType(delegateRelationship.delegateBase));
ObjectType delegateSuperObject = ObjectType.cast(
typeRegistry.getType(codingConvention.getDelegateSuperclassName()));
if (delegatorObject != null &&
delegateBaseObject != null &&
delegateSuperObject != null) {
FunctionType delegatorCtor = delegatorObject.getConstructor();
FunctionType delegateBaseCtor = delegateBaseObject.getConstructor();
FunctionType delegateSuperCtor = delegateSuperObject.getConstructor();
if (delegatorCtor != null && delegateBaseCtor != null &&
delegateSuperCtor != null) {
FunctionParamBuilder functionParamBuilder =
new FunctionParamBuilder(typeRegistry);
functionParamBuilder.addRequiredParams(
getNativeType(U2U_CONSTRUCTOR_TYPE));
FunctionType findDelegate = typeRegistry.createFunctionType(
typeRegistry.createDefaultObjectUnion(delegateBaseObject),
functionParamBuilder.build());
FunctionType delegateProxy = typeRegistry.createConstructorType(
delegateBaseObject.getReferenceName() + DELEGATE_PROXY_SUFFIX,
null, null, null);
delegateProxy.setPrototypeBasedOn(delegateBaseObject);
codingConvention.applyDelegateRelationship(
delegateSuperObject, delegateBaseObject, delegatorObject,
delegateProxy, findDelegate);
delegateProxyPrototypes.add(delegateProxy.getPrototype());
}
}
}
/**
* Declare the symbol for a qualified name in the global scope.
*
* @param info The doc info for this property.
* @param n A top-level GETPROP node (it should not be contained inside
* another GETPROP).
* @param parent The parent of {@code n}.
* @param rhsValue The node that {@code n} is being initialized to,
* or {@code null} if this is a stub declaration.
*/
void maybeDeclareQualifiedName(NodeTraversal t, JSDocInfo info,
Node n, Node parent
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> break;
case Token.GETPROP:
maybeCollectMember(t, child, child, null);
break;
}
}
}
private void maybeCollectMember(NodeTraversal t,
Node member, Node nodeWithJsDocInfo, @Nullable Node value) {
JSDocInfo info = nodeWithJsDocInfo.getJSDocInfo();
// Do nothing if there is no JSDoc type info, or
// if the node is not a member expression, or
// if the member expression is not of the form: this.someProperty.
if (info == null ||
member.getType() != Token.GETPROP ||
member.getFirstChild().getType() != Token.THIS) {
return;
}
member.getFirstChild().setJSType(thisType);
JSType jsType = getDeclaredType(t.getSourceName(), info, member, value);
Node name = member.getLastChild();
if (jsType != null &&
(name.getType() == Token.NAME || name.getType() == Token.STRING)) {
thisType.defineDeclaredProperty(
name.getString(),
jsType,
false /* functions with implementations are not in externs */,
member);
}
}
} // end CollectProperties
}
/**
* A stub declaration without any type information.
*/
private static final class StubDeclaration {
private final Node node;
private final boolean isExtern;
private final String ownerName;
private StubDeclaration(Node node, boolean isExtern, String ownerName) {
this.node = node;
this.isExtern = isExtern;
this.ownerName = ownerName;
}
}
/**
* A shallow traversal of the global scope to build up all classes,
* functions, and methods.
*/
private final class GlobalScopeBuilder extends AbstractScopeBuilder {
private GlobalScopeBuilder(Scope scope) {
super(scope);
}
/**
* Visit a node in the global scope, and add anything it declares to the
* global symbol table.
*
* @param t The current traversal.
* @param n The node being visited.
* @param parent The parent of n
*/
@Override public void visit(NodeTraversal t, Node n, Node parent) {
super.visit(t, n, parent);
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>
switch (n.getType()) {
case Token.ASSIGN:
// Handle typedefs.
checkForOldStyleTypedef(t, n);
break;
case Token.VAR:
// Handle typedefs.
if (n.hasOneChild()) {
checkForOldStyleTypedef(t, n);
checkForTypedef(t, n.getFirstChild(), n.getJSDocInfo());
}
break;
}
}
@Override
void maybeDeclareQualifiedName(
NodeTraversal t, JSDocInfo info,
Node n, Node parent, Node rhsValue) {
checkForTypedef(t, n, info);
super.maybeDeclareQualifiedName(t, info, n, parent, rhsValue);
}
/**
* Handle typedefs.
* @param t The current traversal.
* @param candidate A qualified name node.
* @param info JSDoc comments.
*/
private void checkForTypedef(
NodeTraversal t, Node candidate, JSDocInfo info) {
if (info == null || !info.hasTypedefType()) {
return;
}
String typedef = candidate.getQualifiedName();
if (typedef == null) {
return;
}
// TODO(nicksantos|user): This is a terrible, terrible hack
// to bail out on recusive typedefs. We'll eventually need
// to handle these properly.
typeRegistry.declareType(typedef, getNativeType(UNKNOWN_TYPE));
JSType realType = info.getTypedefType().evaluate(scope, typeRegistry);
if (realType == null) {
compiler.report(
JSError.make(
t.getSourceName(), candidate, MALFORMED_TYPEDEF, typedef));
}
typeRegistry.overwriteDeclaredType(typedef, realType);
if (candidate.getType() == Token.GETPROP) {
defineSlot(candidate, candidate.getParent(),
getNativeType(NO_TYPE), false);
}
}
/**
* Handle typedefs.
* @param t The current traversal.
* @param candidate An ASSIGN or VAR node.
*/
// TODO(nicksantos): Kill this.
private void checkForOldStyleTypedef(NodeTraversal t, Node candidate) {
// old-style typedefs
String typedef = codingConvention.
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>identifyTypeDefAssign(candidate);
if (typedef != null) {
// TODO(nicksantos|user): This is a terrible, terrible hack
// to bail out on recusive typedefs. We'll eventually need
// to handle these properly.
typeRegistry.declareType(typedef, getNativeType(UNKNOWN_TYPE));
JSDocInfo info = candidate.getJSDocInfo();
JSType realType = null;
if (info != null && info.getType() != null) {
realType = info.getType().evaluate(scope, typeRegistry);
}
if (realType == null) {
compiler.report(
JSError.make(
t.getSourceName(), candidate, MALFORMED_TYPEDEF, typedef));
}
typeRegistry.overwriteDeclaredType(typedef, realType);
// Duplicate typedefs get handled when we try to register
// this typedef in the scope.
}
}
} // end GlobalScopeBuilder
/**
* A shallow traversal of a local scope to find all arguments and
* local variables.
*/
private final class LocalScopeBuilder extends AbstractScopeBuilder {
/**
* @param scope The scope that we're builidng.
*/
private LocalScopeBuilder(Scope scope) {
super(scope);
}
/**
* Traverse the scope root and build it.
*/
void build() {
NodeTraversal.traverse(compiler, scope.getRootNode(), this);
}
/**
* Visit a node in a local scope, and add any local variables or catch
* parameters into the local symbol table.
*
* @param t The node traversal.
* @param n The node being visited.
* @param parent The parent of n
*/
@Override public void visit(NodeTraversal t, Node n, Node parent) {
if (n == scope.getRootNode()) return;
if (n.getType() == Token.LP && parent == scope.getRootNode()) {
handleFunctionInputs(parent);
return;
}
super.visit(t, n, parent);
}
/** Handle bleeding functions and function parameters. */
private void handleFunctionInputs(Node fnNode) {
// Handle bleeding functions.
Node fnNameNode = fnNode.getFirstChild();
String fnName = fnNameNode.getString
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>();
if (!fnName.isEmpty()) {
Scope.Var fnVar = scope.getVar(fnName);
if (fnVar == null ||
// Make sure we're not touching a native function. Native
// functions aren't bleeding, but may not have a declaration
// node.
(fnVar.getNameNode() != null &&
// Make sure that the function is actually bleeding by checking
// if has already been declared.
fnVar.getInitialValue() != fnNode)) {
defineSlot(fnNameNode, fnNode, fnNode.getJSType(), false);
}
}
declareArguments(fnNode);
}
/**
* Declares all of a function's arguments.
*/
private void declareArguments(Node functionNode) {
Node astParameters = functionNode.getFirstChild().getNext();
Node body = astParameters.getNext();
FunctionType functionType = (FunctionType) functionNode.getJSType();
if (functionType != null) {
Node jsDocParameters = functionType.getParametersNode();
if (jsDocParameters != null) {
Node jsDocParameter = jsDocParameters.getFirstChild();
for (Node astParameter : astParameters.children()) {
if (jsDocParameter != null) {
defineSlot(astParameter, functionNode,
jsDocParameter.getJSType(), true);
jsDocParameter = jsDocParameter.getNext();
} else {
defineSlot(astParameter, functionNode, null, true);
}
}
}
}
} // end declareArguments
} // end LocalScopeBuilder
/** Find the best JSDoc for the given node. */
static JSDocInfo getBestJSDocInfo(Node n) {
JSDocInfo info = n.getJSDocInfo();
if (info == null) {
Node parent = n.getParent();
int parentType = parent.getType();
if (parentType == Token.NAME) {
info = parent.getJSDocInfo();
if (info == null && parent.getParent().hasOneChild()) {
info = parent.getParent().getJSDocInfo();
}
} else if (parentType == Token.ASSIGN) {
info = parent.getJSDocInfo();
} else if (NodeUtil.isObjectLitKey(parent, parent
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS>/*
* Copyright 2008 The Closure Compiler Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.javascript.jscomp;
import com.google.javascript.jscomp.CheckLevel;
/**
* Class that allows to flexibly manage what to do with a reported
* warning/error.
*
* Guard has several choices:
* - return OFF - suppress the warning/error
* - return WARNING
* - return ERROR report it with high severity
* - return null. Does not know what to do with it. Lets the other guard
* decide what to do with it.
*
* Although the interface is very simple it allows you easyly customize what
* warnings you are interested in.
*
* For example there are could be several implementations:
* StrictGuard - {return ERROR}. All warnings should be treat as errors.
* SilentGuard - {if (WARNING) return OFF}. Suppress all warnings but still
* fail if js has errors.
* WhitelistGuard (if !whitelistErrors.contains(error) return ERROR) return
* error if it does not present in the whitelist.
*
* @author anatol@google.com (Anatol Pomazau)
*/
public abstract class WarningsGuard {
public static enum Priority {
MAX(1),
MIN(100),
STRICT(100),
DEFAULT(50),
SUPPRESS_BY_WHITELIST(40),
SUPPRESS_DOC(20),
FILTER_BY_PATH(1);
final int value;
Priority(int value) {
this.value = value;
}
public int getValue() {
return value;
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> }
}
/**
* Returns a new check level for a given error. OFF - suppress it, ERROR -
* report as error. null means that this guard does not know what to do
* with the error. Null is extremely helpful when you have a chain of
* guards. If current guard returns null, then the next in the chain should
* process it.
*
* @param error a reported error.
* @return what level given error should have.
*/
public abstract CheckLevel level(JSError error);
/**
* The priority in which warnings guards are applied. Lower means the
* guard will be applied sooner. Expressed on a scale of 1 to 100.
*/
protected int getPriority() {
return Priority.DEFAULT.value;
}
/**
* Returns whether all warnings in the given diagnostic group will be
* filtered out. Used to determine which passes to skip.
*
* @param group A group of DiagnosticTypes.
* @return Whether all warnings of these types are disabled by this guard.
*/
protected boolean disables(DiagnosticGroup group) {
return false;
}
/**
* Returns whether any of the warnings in the given diagnostic group will be
* upgraded to a warning or error.
*
* @param group A group of DiagnosticTypes.
* @return Whether any warnings of these types are enabled by this guard.
*/
protected boolean enables(DiagnosticGroup group) {
return false;
}
}
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> where the {@code params} is a comma
* separated list of types, the first one being a special
* {@code this:T} if the function expects a known type for {@code this}.
*/
@Override
public String toString() {
if (this == registry.getNativeType(JSTypeNative.FUNCTION_INSTANCE_TYPE)) {
return "Function";
}
StringBuilder b = new StringBuilder(32);
b.append("function (");
int paramNum = call.parameters.getChildCount();
boolean hasKnownTypeOfThis = !typeOfThis.isUnknownType();
if (hasKnownTypeOfThis) {
if (isConstructor()) {
b.append("new:");
} else {
b.append("this:");
}
b.append(typeOfThis.toString());
}
if (paramNum > 0) {
if (hasKnownTypeOfThis) {
b.append(", ");
}
Node p = call.parameters.getFirstChild();
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
while (p != null) {
b.append(", ");
if (p.isVarArgs()) {
appendVarArgsString(b, p.getJSType());
} else {
b.append(p.getJSType().toString());
}
p = p.getNext();
}
}
b.append("): ");
b.append(call.returnType);
return b.toString();
}
/** Gets the string representation of a var args param. */
private void appendVarArgsString(StringBuilder builder, JSType paramType) {
if (paramType.isUnionType()) {
// Remove the optionalness from the var arg.
paramType = ((UnionType) paramType).getRestrictedUnion(
registry.getNativeType(JSTypeNative.VOID_TYPE));
}
builder.append("...[").append(paramType.toString()).append("]");
}
/**
* A function is a subtype of another if their call methods are related via
* subtyping and {@code this} is a subtype of {@code that} with regard to
* the prototype chain.
*/
@
Closure, 157
<FILEB>
<CHANGES>
if (!n.isQuotedString() &&
TokenStream.isJSIdentifier(name) &&
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(name);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
add(jsString(n.getString(), outputCharsetEncoder));
}
<CHANGEE>
<CHANGES>
Preconditions.checkState(c.getType() == Token.STRING);
String key = c.getString();
<CHANGEE>
<CHANGES>
if (!c.isQuotedString() &&
!TokenStream.isKeyword(key) &&
TokenStream.isJSIdentifier(key) &&
<CHANGEE>
<CHANGES>
NodeUtil.isLatin(key)) {
add(key);
<CHANGEE>
<CHANGES>
double d = getSimpleNumber(key);
if (!Double.isNaN(d)) {
cc.addNumber(d);
} else {
addExpr(c, 1);
}
<CHANGEE>
<CHANGES>
}
static boolean isSimpleNumber(String s) {
int len = s.length();
for (int index = 0; index < len; index++) {
char c = s.charAt(index);
if (c < '0' || c > '9') {
return false;
}
}
return len > 0;
}
static double getSimpleNumber(String s) {
if (isSimpleNumber(s)) {
long l = Long.parseLong(s);
if (l < NodeUtil.MAX_POSITIVE_INTEGER_NUMBER) {
return l;
}
}
return Double.NaN;
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
if (TokenStream.isJSIdentifier(child.getString())) {
<CHANGEE>
<CHANGES>
if (TokenStream.isJSIdentifier(key.getString())) {
<CHANGEE>
<FILEE>
<FILEB>
<CHANGES>
private Node transformNumberAsString(NumberLiteral literalNode) {
JSDocInfo jsDocInfo = handleJsDoc(literalNode);
Node irNode = newStringNode(getStringValue(literalNode.getNumber()));
if (jsDocInfo!= null) {
irNode.setJSDocInfo(jsDocInfo);
}
setSourceInfo(irNode, literalNode);
return irNode;
}
private static String getStringValue(double value) {
long longValue = (long) value;
<CHANGEE>
<CHANGES>
if (longValue == value) {
return Long.toString(longValue);
} else {
return Double.toString(value);
}
}
<CHANGEE>
<CHANGES>
} else if (n instanceof NumberLiteral) {
ret = transformNumberAsString((NumberLiteral)n);
ret.putBooleanProp(Node.QUOTED_PROP, true);
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
<CHANGEE>
<CHANGES>
Preconditions.checkState(ret.getType() == Token.STRING);
<CHANGEE>
<FILEE>
<FILEB>
Preconditions.checkState(first.getType() == Token.FUNCTION);
// Get methods are unnamed
Preconditions.checkState(first.getFirstChild().getString().isEmpty());
if (type == Token.GET) {
// Get methods have no parameters.
Preconditions.checkState(!first.getChildAtIndex(1).hasChildren());
add("get ");
} else {
// Set methods have one parameter.
Preconditions.checkState(first.getChildAtIndex(1).hasOneChild());
add("set ");
}
// The name is on the GET or SET node.
String name = n.getString();
Node fn = first;
Node parameters = fn.getChildAtIndex(1);
Node body = fn.getLastChild();
// Add the property name.
<CHANGES>
if (TokenStream.isJSIdentifier(name) &&
<CHANGEE>
// do not encode literally any non-literal characters that were
// unicode escaped.
NodeUtil.isLatin(name)) {
add(name);
} else {
// Determine if the string is a simple number.
<CHANGES>
add(jsString(n.getString(), outputCharsetEncoder));
<CHANGEE>
}
add(parameters);
add(body, Context.PRESERVE_BLOCK);
break;
case Token.SCRIPT:
case Token.BLOCK: {
if (n.getClass() != Node.class) {
throw new Error("Unexpected Node subclass.");
}
boolean preserveBlock = context == Context.PRESERVE_BLOCK;
if (preserveBlock) {
cc.beginBlock();
case Token.DELPROP:
Preconditions.checkState(childCount == 1);
add("delete ");
add(first);
break;
case Token.OBJECTLIT: {
boolean needsParens = (context == Context.START_OF_EXPR);
if (needsParens) {
add("(");
}
add("{");
for (Node c = first; c != null; c = c.getNext()) {
if (c != first) {
cc.listSeparator();
}
if (c.getType() == Token.GET || c.getType() == Token.SET) {
add(c);
} else {
<CHANGES>
<CHANGEE>
// Object literal property names don't have to be quoted if they
// are not JavaScript keywords
<CHANGES>
if (c.<SCANS> hasKnownTypeOfThis = !typeOfThis.isUnknownType();
if (hasKnownTypeOfThis) {
b.append("this:");
b.append(getDebugHashCodeStringOf(typeOfThis));
}
if (paramNum > 0) {
if (hasKnownTypeOfThis) {
b.append(", ");
}
Node p = call.parameters.getFirstChild();
b.append(getDebugHashCodeStringOf(p.getJSType()));
p = p.getNext();
while (p != null) {
b.append(", ");
b.append(getDebugHashCodeStringOf(p.getJSType()));
p = p.getNext();
}
}
b.append(")");
b.append(": ");
b.append(getDebugHashCodeStringOf(call.returnType));
return b.toString();
}
private String getDebugHashCodeStringOf(JSType type) {
if (type == this) {
return "me";
} else {
return type.toDebugHashCodeString();
}
}
}